[3/4] mount: Bind-mount root via userns_call

Submitted by Radostin Stoyanov on Nov. 10, 2019, 9:15 a.m.

Details

Message ID 20191110091523.24426-3-rstoyanov1@gmail.com
State New
Series "Series without cover letter"
Headers show

Commit Message

Radostin Stoyanov Nov. 10, 2019, 9:15 a.m.
When restoring a runc container with enabled user namespace CRIU fails
to mount the specified root directory because the path is under
/run/runc which is inaccessible to unprivileged users.

Signed-off-by: Radostin Stoyanov <rstoyanov1@gmail.com>
---
 criu/mount.c | 51 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 39 insertions(+), 12 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/mount.c b/criu/mount.c
index d6789d93b..d180110ac 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -2030,20 +2030,20 @@  static char *mnt_fsname(struct mount_info *mi)
 	return mi->fstype->name;
 }
 
-static int apply_sb_flags(void *args, int fd, pid_t pid)
+static int userns_mount(char *src, void *args, int fd, pid_t pid)
 {
 	unsigned long flags = *(unsigned long *) args;
 	int rst = -1, err = -1;
-	char path[PSFDS];
+	char target[PSFDS];
 
-	snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
+	snprintf(target, sizeof(target), "/proc/self/fd/%d", fd);
 
 	if (pid != getpid() && switch_ns(pid, &mnt_ns_desc, &rst))
 		return -1;
 
-	err = mount(NULL, path, NULL, MS_REMOUNT | flags, NULL);
+	err = mount(src, target, NULL, flags, NULL);
 	if (err)
-		pr_perror("Unable to remount %s", path);
+		pr_perror("Unable to mount %s", target);
 
 	if (rst >= 0 &&	restore_ns(rst, &mnt_ns_desc))
 		return -1;
@@ -2051,6 +2051,16 @@  static int apply_sb_flags(void *args, int fd, pid_t pid)
 	return err;
 }
 
+static int apply_sb_flags(void *args, int fd, pid_t pid)
+{
+	return userns_mount(NULL, args, fd, pid);
+}
+
+static int mount_root(void *args, int fd, pid_t pid)
+{
+	return userns_mount(opts.root, args, fd, pid);
+}
+
 static int do_new_mount(struct mount_info *mi)
 {
 	unsigned long sflags = mi->sb_flags;
@@ -2098,10 +2108,9 @@  static int do_new_mount(struct mount_info *mi)
 			pr_perror("Unable to open %s", mi->mountpoint);
 			return -1;
 		}
-		sflags |= MS_RDONLY;
-		if (userns_call(apply_sb_flags, 0,
-				&sflags, sizeof(sflags), fd)) {
-			pr_perror("Unable to apply mount flags %d for %s",
+		sflags |= MS_RDONLY | MS_REMOUNT;
+		if (userns_call(apply_sb_flags, 0, &sflags, sizeof(sflags), fd)) {
+			pr_err("Unable to apply mount flags %d for %s",
 						mi->sb_flags, mi->mountpoint);
 			close(fd);
 			return -1;
@@ -2501,15 +2510,33 @@  static int do_mount_one(struct mount_info *mi)
 	pr_debug("\tMounting %s @%s (%d)\n", mi->fstype->name, mi->mountpoint, mi->need_plugin);
 
 	if (rst_mnt_is_root(mi)) {
+		int fd;
+		unsigned long flags = MS_BIND | MS_REC;
+
 		if (opts.root == NULL) {
 			pr_err("The --root option is required to restore a mount namespace\n");
 			return -1;
 		}
 
 		/* do_mount_root() is called from populate_mnt_ns() */
-		if (mount(opts.root, mi->mountpoint, NULL, MS_BIND | MS_REC, NULL)) {
-			pr_perror("mount %s %s", opts.root, mi->mountpoint);
-			return -1;
+		if (root_ns_mask & CLONE_NEWUSER) {
+			fd = open(mi->mountpoint, O_PATH);
+			if (fd < 0) {
+				pr_perror("Unable to open %s", mi->mountpoint);
+				return -1;
+			}
+
+			if (userns_call(mount_root, 0, &flags, sizeof(flags), fd)) {
+				pr_err("Unable to mount %s\n", mi->mountpoint);
+				close(fd);
+				return -1;
+			}
+			close(fd);
+		} else {
+			if (mount(opts.root, mi->mountpoint, NULL, flags, NULL)) {
+				pr_perror("mount %s %s", opts.root, mi->mountpoint);
+				return -1;
+			}
 		}
 
 		if (do_mount_root(mi))