Skip to content

Commit 2462651

Browse files
committed
fs: allow changing idmappings
This patchset makes it possible to create a new idmapped mount from an already idmapped mount and to clear idmappings. // Create a first idmapped mount struct mount_attr attr = { .attr_set = MOUNT_ATTR_IDMAP .userns_fd = fd_userns }; fd_tree = open_tree(-EBADF, "/", OPEN_TREE_CLONE, &attr, sizeof(attr)); move_mount(fd_tree, "", -EBADF, "/mnt", MOVE_MOUNT_F_EMPTY_PATH); // Create a second idmapped mount from the first idmapped mount attr.attr_set = MOUNT_ATTR_IDMAP; attr.userns_fd = fd_userns2; fd_tree2 = open_tree(-EBADF, "/mnt", OPEN_TREE_CLONE, &attr, sizeof(attr)); // Create a second non-idmapped mount from the first idmapped mount: memset(&attr, 0, sizeof(attr)); attr.attr_clr = MOUNT_ATTR_IDMAP; fd_tree2 = open_tree(-EBADF, "/mnt", OPEN_TREE_CLONE, &attr, sizeof(attr)); Link: https://lore.kernel.org/r/20250128-work-mnt_idmap-update-v2-v1-5-c25feb0d2eb3@kernel.org Reviewed-by: "Seth Forshee (DigitalOcean)" <sforshee@kernel.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 325cca8 commit 2462651

File tree

1 file changed

+32
-21
lines changed

1 file changed

+32
-21
lines changed

fs/namespace.c

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static LIST_HEAD(mnt_ns_list); /* protected by mnt_ns_tree_lock */
8989

9090
enum mount_kattr_flags_t {
9191
MOUNT_KATTR_RECURSE = (1 << 0),
92+
MOUNT_KATTR_IDMAP_REPLACE = (1 << 1),
9293
};
9394

9495
struct mount_kattr {
@@ -4612,11 +4613,10 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
46124613
return -EINVAL;
46134614

46144615
/*
4615-
* Once a mount has been idmapped we don't allow it to change its
4616-
* mapping. It makes things simpler and callers can just create
4617-
* another bind-mount they can idmap if they want to.
4616+
* We only allow an mount to change it's idmapping if it has
4617+
* never been accessible to userspace.
46184618
*/
4619-
if (is_idmapped_mnt(m))
4619+
if (!(kattr->kflags & MOUNT_KATTR_IDMAP_REPLACE) && is_idmapped_mnt(m))
46204620
return -EPERM;
46214621

46224622
/* The underlying filesystem doesn't support idmapped mounts yet. */
@@ -4706,18 +4706,16 @@ static int mount_setattr_prepare(struct mount_kattr *kattr, struct mount *mnt)
47064706

47074707
static void do_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
47084708
{
4709+
struct mnt_idmap *old_idmap;
4710+
47094711
if (!kattr->mnt_idmap)
47104712
return;
47114713

4712-
/*
4713-
* Pairs with smp_load_acquire() in mnt_idmap().
4714-
*
4715-
* Since we only allow a mount to change the idmapping once and
4716-
* verified this in can_idmap_mount() we know that the mount has
4717-
* @nop_mnt_idmap attached to it. So there's no need to drop any
4718-
* references.
4719-
*/
4714+
old_idmap = mnt_idmap(&mnt->mnt);
4715+
4716+
/* Pairs with smp_load_acquire() in mnt_idmap(). */
47204717
smp_store_release(&mnt->mnt.mnt_idmap, mnt_idmap_get(kattr->mnt_idmap));
4718+
mnt_idmap_put(old_idmap);
47214719
}
47224720

47234721
static void mount_setattr_commit(struct mount_kattr *kattr, struct mount *mnt)
@@ -4826,13 +4824,23 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize,
48264824
if (!((attr->attr_set | attr->attr_clr) & MOUNT_ATTR_IDMAP))
48274825
return 0;
48284826

4829-
/*
4830-
* We currently do not support clearing an idmapped mount. If this ever
4831-
* is a use-case we can revisit this but for now let's keep it simple
4832-
* and not allow it.
4833-
*/
4834-
if (attr->attr_clr & MOUNT_ATTR_IDMAP)
4835-
return -EINVAL;
4827+
if (attr->attr_clr & MOUNT_ATTR_IDMAP) {
4828+
/*
4829+
* We can only remove an idmapping if it's never been
4830+
* exposed to userspace.
4831+
*/
4832+
if (!(kattr->kflags & MOUNT_KATTR_IDMAP_REPLACE))
4833+
return -EINVAL;
4834+
4835+
/*
4836+
* Removal of idmappings is equivalent to setting
4837+
* nop_mnt_idmap.
4838+
*/
4839+
if (!(attr->attr_set & MOUNT_ATTR_IDMAP)) {
4840+
kattr->mnt_idmap = &nop_mnt_idmap;
4841+
return 0;
4842+
}
4843+
}
48364844

48374845
if (attr->userns_fd > INT_MAX)
48384846
return -EINVAL;
@@ -4923,8 +4931,10 @@ static int build_mount_kattr(const struct mount_attr *attr, size_t usize,
49234931

49244932
static void finish_mount_kattr(struct mount_kattr *kattr)
49254933
{
4926-
put_user_ns(kattr->mnt_userns);
4927-
kattr->mnt_userns = NULL;
4934+
if (kattr->mnt_userns) {
4935+
put_user_ns(kattr->mnt_userns);
4936+
kattr->mnt_userns = NULL;
4937+
}
49284938

49294939
if (kattr->mnt_idmap)
49304940
mnt_idmap_put(kattr->mnt_idmap);
@@ -5019,6 +5029,7 @@ SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename,
50195029
int ret;
50205030
struct mount_kattr kattr = {};
50215031

5032+
kattr.kflags = MOUNT_KATTR_IDMAP_REPLACE;
50225033
if (flags & AT_RECURSIVE)
50235034
kattr.kflags |= MOUNT_KATTR_RECURSE;
50245035

0 commit comments

Comments
 (0)