Skip to content

Commit

Permalink
Merge tag 'fs.move_mount.move_mount_set_group.v5.15' of git://git.ker…
Browse files Browse the repository at this point in the history
…nel.org/pub/scm/linux/kernel/git/brauner/linux

Pull move_mount updates from Christian Brauner:
 "This contains an extension to the move_mount() syscall making it
  possible to add a single private mount into an existing propagation
  tree.

  The use-case comes from the criu folks which have been struggling with
  restoring complex mount trees for a long time. Variations of this work
  have been discussed at Plumbers before, e.g.

      https://www.linuxplumbersconf.org/event/7/contributions/640/

  The extension to move_mount() enables criu to restore any set of mount
  namespaces, mount trees and sharing group trees without introducing
  yet more complexity into mount propagation itself.

  The changes required to criu to make use of this and restore complex
  propagation trees are available at

      https://github.com/Snorch/criu/commits/mount-v2-poc

  A cleaned-up version of this will go up for merging into the main criu
  repo after this lands"

* tag 'fs.move_mount.move_mount_set_group.v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux:
  tests: add move_mount(MOVE_MOUNT_SET_GROUP) selftest
  move_mount: allow to add a mount into an existing group
  • Loading branch information
torvalds committed Aug 31, 2021
2 parents 0ee7c3e + 8374f43 commit 1dd5915
Show file tree
Hide file tree
Showing 7 changed files with 463 additions and 2 deletions.
77 changes: 76 additions & 1 deletion fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2694,6 +2694,78 @@ static bool check_for_nsfs_mounts(struct mount *subtree)
return ret;
}

static int do_set_group(struct path *from_path, struct path *to_path)
{
struct mount *from, *to;
int err;

from = real_mount(from_path->mnt);
to = real_mount(to_path->mnt);

namespace_lock();

err = -EINVAL;
/* To and From must be mounted */
if (!is_mounted(&from->mnt))
goto out;
if (!is_mounted(&to->mnt))
goto out;

err = -EPERM;
/* We should be allowed to modify mount namespaces of both mounts */
if (!ns_capable(from->mnt_ns->user_ns, CAP_SYS_ADMIN))
goto out;
if (!ns_capable(to->mnt_ns->user_ns, CAP_SYS_ADMIN))
goto out;

err = -EINVAL;
/* To and From paths should be mount roots */
if (from_path->dentry != from_path->mnt->mnt_root)
goto out;
if (to_path->dentry != to_path->mnt->mnt_root)
goto out;

/* Setting sharing groups is only allowed across same superblock */
if (from->mnt.mnt_sb != to->mnt.mnt_sb)
goto out;

/* From mount root should be wider than To mount root */
if (!is_subdir(to->mnt.mnt_root, from->mnt.mnt_root))
goto out;

/* From mount should not have locked children in place of To's root */
if (has_locked_children(from, to->mnt.mnt_root))
goto out;

/* Setting sharing groups is only allowed on private mounts */
if (IS_MNT_SHARED(to) || IS_MNT_SLAVE(to))
goto out;

/* From should not be private */
if (!IS_MNT_SHARED(from) && !IS_MNT_SLAVE(from))
goto out;

if (IS_MNT_SLAVE(from)) {
struct mount *m = from->mnt_master;

list_add(&to->mnt_slave, &m->mnt_slave_list);
to->mnt_master = m;
}

if (IS_MNT_SHARED(from)) {
to->mnt_group_id = from->mnt_group_id;
list_add(&to->mnt_share, &from->mnt_share);
lock_mount_hash();
set_mnt_shared(to);
unlock_mount_hash();
}

err = 0;
out:
namespace_unlock();
return err;
}

static int do_move_mount(struct path *old_path, struct path *new_path)
{
struct mnt_namespace *ns;
Expand Down Expand Up @@ -3678,7 +3750,10 @@ SYSCALL_DEFINE5(move_mount,
if (ret < 0)
goto out_to;

ret = do_move_mount(&from_path, &to_path);
if (flags & MOVE_MOUNT_SET_GROUP)
ret = do_set_group(&from_path, &to_path);
else
ret = do_move_mount(&from_path, &to_path);

out_to:
path_put(&to_path);
Expand Down
3 changes: 2 additions & 1 deletion include/uapi/linux/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@
#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
#define MOVE_MOUNT__MASK 0x00000077
#define MOVE_MOUNT_SET_GROUP 0x00000100 /* Set sharing group instead */
#define MOVE_MOUNT__MASK 0x00000177

/*
* fsopen() flags.
Expand Down
1 change: 1 addition & 0 deletions tools/testing/selftests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ TARGETS += memory-hotplug
TARGETS += mincore
TARGETS += mount
TARGETS += mount_setattr
TARGETS += move_mount_set_group
TARGETS += mqueue
TARGETS += nci
TARGETS += net
Expand Down
1 change: 1 addition & 0 deletions tools/testing/selftests/move_mount_set_group/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
move_mount_set_group_test
7 changes: 7 additions & 0 deletions tools/testing/selftests/move_mount_set_group/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for mount selftests.
CFLAGS = -g -I../../../../usr/include/ -Wall -O2

TEST_GEN_FILES += move_mount_set_group_test

include ../lib.mk
1 change: 1 addition & 0 deletions tools/testing/selftests/move_mount_set_group/config
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_USER_NS=y
Loading

0 comments on commit 1dd5915

Please sign in to comment.