Skip to content

Commit 0200679

Browse files
committed
tmpfs: verify {g,u}id mount options correctly
A while ago we received the following report: "The other outstanding issue I noticed comes from the fact that fsconfig syscalls may occur in a different userns than that which called fsopen. That means that resolving the uid/gid via current_user_ns() can save a kuid that isn't mapped in the associated namespace when the filesystem is finally mounted. This means that it is possible for an unprivileged user to create files owned by any group in a tmpfs mount (since we can set the SUID bit on the tmpfs directory), or a tmpfs that is owned by any user, including the root group/user." The contract for {g,u}id mount options and {g,u}id values in general set from userspace has always been that they are translated according to the caller's idmapping. In so far, tmpfs has been doing the correct thing. But since tmpfs is mountable in unprivileged contexts it is also necessary to verify that the resulting {k,g}uid is representable in the namespace of the superblock to avoid such bugs as above. The new mount api's cross-namespace delegation abilities are already widely used. After having talked to a bunch of userspace this is the most faithful solution with minimal regression risks. I know of one users - systemd - that makes use of the new mount api in this way and they don't set unresolable {g,u}ids. So the regression risk is minimal. Link: https://lore.kernel.org/lkml/CALxfFW4BXhEwxR0Q5LSkg-8Vb4r2MONKCcUCVioehXQKr35eHg@mail.gmail.com Fixes: f323562 ("vfs: Convert ramfs, shmem, tmpfs, devtmpfs, rootfs to use the new mount API") Reviewed-by: "Seth Forshee (DigitalOcean)" <[email protected]> Reported-by: Seth Jenkins <[email protected]> Message-Id: <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 3c1b752 commit 0200679

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

mm/shmem.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3793,6 +3793,8 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
37933793
unsigned long long size;
37943794
char *rest;
37953795
int opt;
3796+
kuid_t kuid;
3797+
kgid_t kgid;
37963798

37973799
opt = fs_parse(fc, shmem_fs_parameters, param, &result);
37983800
if (opt < 0)
@@ -3828,14 +3830,32 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
38283830
ctx->mode = result.uint_32 & 07777;
38293831
break;
38303832
case Opt_uid:
3831-
ctx->uid = make_kuid(current_user_ns(), result.uint_32);
3832-
if (!uid_valid(ctx->uid))
3833+
kuid = make_kuid(current_user_ns(), result.uint_32);
3834+
if (!uid_valid(kuid))
38333835
goto bad_value;
3836+
3837+
/*
3838+
* The requested uid must be representable in the
3839+
* filesystem's idmapping.
3840+
*/
3841+
if (!kuid_has_mapping(fc->user_ns, kuid))
3842+
goto bad_value;
3843+
3844+
ctx->uid = kuid;
38343845
break;
38353846
case Opt_gid:
3836-
ctx->gid = make_kgid(current_user_ns(), result.uint_32);
3837-
if (!gid_valid(ctx->gid))
3847+
kgid = make_kgid(current_user_ns(), result.uint_32);
3848+
if (!gid_valid(kgid))
38383849
goto bad_value;
3850+
3851+
/*
3852+
* The requested gid must be representable in the
3853+
* filesystem's idmapping.
3854+
*/
3855+
if (!kgid_has_mapping(fc->user_ns, kgid))
3856+
goto bad_value;
3857+
3858+
ctx->gid = kgid;
38393859
break;
38403860
case Opt_huge:
38413861
ctx->huge = result.uint_32;

0 commit comments

Comments
 (0)