diff options
author | Evgeny Vereshchagin <evvers@ya.ru> | 2016-10-20 09:03:40 +0000 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2016-10-23 23:23:40 -0400 |
commit | 63eae72312b6b8df4c7186233994a65d747229a7 (patch) | |
tree | ee0bc4e142129e205f4388fb7e482f6e58ab50bb /src/nspawn | |
parent | 548bd57376f7eb82cc792f0476688ccc9843962a (diff) |
nspawn: really lchown(uid/gid)
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
Diffstat (limited to 'src/nspawn')
-rw-r--r-- | src/nspawn/nspawn-mount.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 44dc9bfcf4..115de64cf9 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -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); |