[Devel] [PATCH rh7 09/11] ms/quota: Ensure qids map to the filesystem
Konstantin Khorenko
khorenko at virtuozzo.com
Thu Jun 22 17:47:56 MSK 2017
From: "Eric W. Biederman" <ebiederm at xmission.com>
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;
--
1.8.3.1
More information about the Devel
mailing list