[Devel] [PATCH RHEL7 COMMIT] ms/quota: Ensure qids map to the filesystem

Konstantin Khorenko khorenko at virtuozzo.com
Tue Jul 11 18:39:41 MSK 2017


The commit is pushed to "branch-rh7-3.10.0-514.26.1.vz7.33.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-514.26.1.vz7.33.3
------>
commit 6e13100e43666b3ee691cb1eb46fce150d41e3dc
Author: Eric W. Biederman <ebiederm at xmission.com>
Date:   Tue Jul 11 19:39:41 2017 +0400

    ms/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 at suse.cz>
    Acked-by: Seth Forshee <seth.forshee at canonical.com>
    Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
    (cherry picked from commit d49d37624a1931c2f3b5d0cbe95bd5181cbdc279)
    
    https://jira.sw.ru/browse/PSBM-40075
    
    Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 fs/quota/dquot.c      |  3 +++
 fs/quota/quota.c      | 12 ++++++------
 include/linux/quota.h | 10 ++++++++++
 3 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 89089a9..df89720 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -825,6 +825,9 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
 	unsigned int hashent = hashfn(sb, qid);
 	struct dquot *dquot = NULL, *empty = NULL;
 
+	if (!qid_has_mapping(sb->s_user_ns, qid))
+		return ERR_PTR(-EINVAL);
+
         if (!sb_has_quota_active(sb, qid.type))
 		return NULL;
 we_slept:
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 6611d8c..3853373 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -140,7 +140,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)
@@ -166,7 +166,7 @@ static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
 	if (!sb_has_nextdqblk(sb) || !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)
@@ -217,7 +217,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);
@@ -283,7 +283,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;
 	return sb->s_qcop->set_dqblk(sb, qid, &fdq);
 }
@@ -298,7 +298,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, &fdq);
 	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
@@ -321,7 +321,7 @@ static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
 	if (!sb_has_nextdqblk(sb) || !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)
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 7e955f0..e148af3 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -175,6 +175,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;
 


More information about the Devel mailing list