]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: really lchown(uid/gid)
authorEvgeny Vereshchagin <evvers@ya.ru>
Thu, 20 Oct 2016 09:03:40 +0000 (09:03 +0000)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 24 Oct 2016 03:23:40 +0000 (23:23 -0400)
https://github.com/systemd/systemd/pull/4372#issuecomment-253723849:

* `mount_all (outer_child)` creates `container_dir/sys/fs/selinux`
* `mount_all (outer_child)` doesn't patch `container_dir/sys/fs` and so on.
* `mount_sysfs (inner_child)` tries to create `/sys/fs/cgroup`
* This fails

370   stat("/sys/fs", {st_dev=makedev(0, 28), st_ino=13880, st_mode=S_IFDIR|0755, st_nlink=3, st_uid=65534, st_gid=65534, st_blksize=4096, st_blocks=0, st_size=60, st_atime=2016/10/14-05:16:43.398665943, st_mtime=2016/10/14-05:16:43.399665943, st_ctime=2016/10/14-05:16:43.399665943}) = 0
370   mkdir("/sys/fs/cgroup", 0755)     = -1 EACCES (Permission denied)

* `mount_syfs (inner_child)` ignores that error and

mount(NULL, "/sys", NULL, MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_REMOUNT|MS_BIND, NULL) = 0

* `mount_cgroups` finally fails

src/nspawn/nspawn-mount.c

index 44dc9bfcf4ab3afca76cf6ba8d1c94b01fba4f3e..115de64cf934f3a098d9f0b376bec2d0bda1e962 100644 (file)
@@ -300,6 +300,59 @@ int mount_sysfs(const char *dest) {
                              MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL);
 }
 
+static int mkdir_userns(const char *path, mode_t mode, bool in_userns, uid_t uid_shift) {
+        int r;
+
+        assert(path);
+
+        r = mkdir(path, mode);
+        if (r < 0 && errno != EEXIST)
+                return -errno;
+
+        if (!in_userns) {
+                r = lchown(path, uid_shift, uid_shift);
+                if (r < 0)
+                        return -errno;
+        }
+
+        return 0;
+}
+
+static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, bool in_userns, uid_t uid_shift) {
+        const char *p, *e;
+        int r;
+
+        assert(path);
+
+        if (prefix && !path_startswith(path, prefix))
+                return -ENOTDIR;
+
+        /* create every parent directory in the path, except the last component */
+        p = path + strspn(path, "/");
+        for (;;) {
+                char t[strlen(path) + 1];
+
+                e = p + strcspn(p, "/");
+                p = e + strspn(e, "/");
+
+                /* Is this the last component? If so, then we're done */
+                if (*p == 0)
+                        break;
+
+                memcpy(t, path, e - path);
+                t[e-path] = 0;
+
+                if (prefix && path_startswith(prefix, t))
+                        continue;
+
+                r = mkdir_userns(t, mode, in_userns, uid_shift);
+                if (r < 0)
+                        return r;
+        }
+
+        return mkdir_userns(path, mode, in_userns, uid_shift);
+}
+
 int mount_all(const char *dest,
               bool use_userns, bool in_userns,
               bool use_netns,
@@ -361,7 +414,7 @@ int mount_all(const char *dest,
                 if (mount_table[k].what && r > 0)
                         continue;
 
-                r = mkdir_p(where, 0755);
+                r = mkdir_userns_p(dest, where, 0755, in_userns, uid_shift);
                 if (r < 0 && r != -EEXIST) {
                         if (mount_table[k].fatal)
                                 return log_error_errno(r, "Failed to create directory %s: %m", where);