Map uid/gid to global kuid/kgid before pass it down to quota infrastructure. Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> --- fs/quota/quota.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 files changed, 36 insertions(+), 9 deletions(-) diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 6f15578..a59efd4 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -19,8 +19,13 @@ #include <linux/writeback.h> static int check_quotactl_permission(struct super_block *sb, int type, int cmd, - qid_t id) + qid_t id, qid_t* global_id) { + kuid_t kuid; + kgid_t kgid; + struct user_namespace *ns = current_user_ns(); + int is_get_query = 0; + switch (cmd) { /* these commands do not require any special privilegues */ case Q_GETFMT: @@ -29,11 +34,32 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd, case Q_XGETQSTAT: case Q_XQUOTASYNC: break; - /* allow to query information for dquots we "own" */ case Q_GETQUOTA: case Q_XGETQUOTA: - if ((type == USRQUOTA && current_euid() == id) || - (type == GRPQUOTA && in_egroup_p(id))) + is_get_query = 1; + case Q_SETQUOTA: + case Q_XSETQLIM: + /* Map to global user namespace */ + switch (type) { + case USRQUOTA: + kuid = make_kuid(ns, id); + if (!uid_valid(kuid)) + return -EINVAL; + *global_id = from_kuid_munged(&init_user_ns, kuid); + break; + case GRPQUOTA: + kgid = make_kgid(ns, id); + if (!gid_valid(kgid)) + return -EINVAL; + *global_id = from_kgid_munged(&init_user_ns, kgid); + break; + default: + return -EINVAL; + } + /* allow to query information for dquots we "own" */ + if (is_get_query && + ((type == USRQUOTA && uid_eq(current_euid(), kuid)) || + (type == GRPQUOTA && in_egroup_p(kgid)))) break; /*FALLTHROUGH*/ default: @@ -240,13 +266,14 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void __user *addr, struct path *path) { int ret; + qid_t qid = -1; if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS)) return -EINVAL; if (!sb->s_qcop) return -ENOSYS; - ret = check_quotactl_permission(sb, type, cmd, id); + ret = check_quotactl_permission(sb, type, cmd, id, &qid); if (ret < 0) return ret; @@ -264,9 +291,9 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, case Q_SETINFO: return quota_setinfo(sb, type, addr); case Q_GETQUOTA: - return quota_getquota(sb, type, id, addr); + return quota_getquota(sb, type, qid, addr); case Q_SETQUOTA: - return quota_setquota(sb, type, id, addr); + return quota_setquota(sb, type, qid, addr); case Q_SYNC: if (!sb->s_qcop->quota_sync) return -ENOSYS; @@ -278,9 +305,9 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, case Q_XGETQSTAT: return quota_getxstate(sb, addr); case Q_XSETQLIM: - return quota_setxquota(sb, type, id, addr); + return quota_setxquota(sb, type, qid, addr); case Q_XGETQUOTA: - return quota_getxquota(sb, type, id, addr); + return quota_getxquota(sb, type, qid, addr); case Q_XQUOTASYNC: if (sb->s_flags & MS_RDONLY) return -EROFS; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html