quota: Ensure qids map to the filesystem
Introduce the helper qid_has_mapping and use it to ensure that the quota system only considers qids that map to the filesystems s_user_ns. In practice for quota supporting filesystems today this is the exact same check as qid_valid. As only 0xffffffff aka (qid_t)-1 does not map into init_user_ns. Replace the qid_valid calls with qid_has_mapping as values come in from userspace. This is harmless today and it prepares the quota system to work on filesystems with quotas but mounted by unprivileged users. Call qid_has_mapping from dqget. This ensures the passed in qid has a prepresentation on the underlying filesystem. Previously this was unnecessary as filesystesm never had qids that could not map. With the introduction of filesystems outside of s_user_ns this will not remain true. All of this ensures the quota code never has to deal with qids that don't map to the underlying filesystem. Cc: Jan Kara <jack@suse.cz> Acked-by: Seth Forshee <seth.forshee@canonical.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
parent
036d523641
commit
d49d37624a
|
@ -841,6 +841,9 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
|
|||
unsigned int hashent = hashfn(sb, qid);
|
||||
struct dquot *dquot, *empty = NULL;
|
||||
|
||||
if (!qid_has_mapping(sb->s_user_ns, qid))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!sb_has_quota_active(sb, qid.type))
|
||||
return ERR_PTR(-ESRCH);
|
||||
we_slept:
|
||||
|
|
|
@ -211,7 +211,7 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
|
|||
if (!sb->s_qcop->get_dqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
if (!qid_has_mapping(sb->s_user_ns, qid))
|
||||
return -EINVAL;
|
||||
ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
|
||||
if (ret)
|
||||
|
@ -237,7 +237,7 @@ static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
|
|||
if (!sb->s_qcop->get_nextdqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
if (!qid_has_mapping(sb->s_user_ns, qid))
|
||||
return -EINVAL;
|
||||
ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
|
||||
if (ret)
|
||||
|
@ -288,7 +288,7 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,
|
|||
if (!sb->s_qcop->set_dqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
if (!qid_has_mapping(sb->s_user_ns, qid))
|
||||
return -EINVAL;
|
||||
copy_from_if_dqblk(&fdq, &idq);
|
||||
return sb->s_qcop->set_dqblk(sb, qid, &fdq);
|
||||
|
@ -581,7 +581,7 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
|||
if (!sb->s_qcop->set_dqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
if (!qid_has_mapping(sb->s_user_ns, qid))
|
||||
return -EINVAL;
|
||||
/* Are we actually setting timer / warning limits for all users? */
|
||||
if (from_kqid(&init_user_ns, qid) == 0 &&
|
||||
|
@ -642,7 +642,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
|
|||
if (!sb->s_qcop->get_dqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
if (!qid_has_mapping(sb->s_user_ns, qid))
|
||||
return -EINVAL;
|
||||
ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
|
||||
if (ret)
|
||||
|
@ -669,7 +669,7 @@ static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
|
|||
if (!sb->s_qcop->get_nextdqblk)
|
||||
return -ENOSYS;
|
||||
qid = make_kqid(current_user_ns(), type, id);
|
||||
if (!qid_valid(qid))
|
||||
if (!qid_has_mapping(sb->s_user_ns, qid))
|
||||
return -EINVAL;
|
||||
ret = sb->s_qcop->get_nextdqblk(sb, &qid, &qdq);
|
||||
if (ret)
|
||||
|
|
|
@ -179,6 +179,16 @@ static inline struct kqid make_kqid_projid(kprojid_t projid)
|
|||
return kqid;
|
||||
}
|
||||
|
||||
/**
|
||||
* qid_has_mapping - Report if a qid maps into a user namespace.
|
||||
* @ns: The user namespace to see if a value maps into.
|
||||
* @qid: The kernel internal quota identifier to test.
|
||||
*/
|
||||
static inline bool qid_has_mapping(struct user_namespace *ns, struct kqid qid)
|
||||
{
|
||||
return from_kqid(ns, qid) != (qid_t) -1;
|
||||
}
|
||||
|
||||
|
||||
extern spinlock_t dq_data_lock;
|
||||
|
||||
|
|
Loading…
Reference in New Issue