diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2016-10-23 23:25:57 -0400 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2016-10-23 23:25:57 -0400 |
commit | 60f17f75d10638975ee05bda11cb02ee8b5cbf10 (patch) | |
tree | 037fe2f986c45833ac4da557f9b327f494a7c8e6 | |
parent | 4e5a239fb86149ff8f370dbe99430e3244bfad44 (diff) | |
parent | 844da987ef8b8c98f837d3328eeb3ed481f43835 (diff) |
Merge pull request #4372 from evverx/fix-synced-cgroup-hierarchy-perms
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/basic/mount-util.c | 2 | ||||
-rw-r--r-- | src/nspawn/nspawn-mount.c | 55 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 8 | ||||
-rw-r--r-- | test/TEST-13-NSPAWN-SMOKE/Makefile | 4 | ||||
-rw-r--r-- | test/TEST-13-NSPAWN-SMOKE/has-overflow.c | 143 | ||||
-rwxr-xr-x | test/TEST-13-NSPAWN-SMOKE/test.sh | 19 |
7 files changed, 63 insertions, 169 deletions
diff --git a/Makefile.am b/Makefile.am index c49edef7b2..04e1b71e9e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6034,7 +6034,6 @@ EXTRA_DIST += \ test/TEST-12-ISSUE-3171/Makefile \ test/TEST-12-ISSUE-3171/test.sh \ test/TEST-13-NSPAWN-SMOKE/Makefile \ - test/TEST-13-NSPAWN-SMOKE/has-overflow.c \ test/TEST-13-NSPAWN-SMOKE/create-busybox-container \ test/TEST-13-NSPAWN-SMOKE/test.sh \ test/test-functions diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 0ef00676ef..2985cc475a 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -162,7 +162,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { fallback_fdinfo: r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); - if (r == -EOPNOTSUPP) + if (IN_SET(r, -EOPNOTSUPP, -EACCES)) goto fallback_fstat; if (r < 0) return r; 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); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 2cbe563953..295293858e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2684,6 +2684,10 @@ static int inner_child( } } + r = reset_uid_gid(); + if (r < 0) + return log_error_errno(r, "Couldn't become new root: %m"); + r = mount_all(NULL, arg_userns_mode != USER_NAMESPACE_NO, true, @@ -2726,10 +2730,6 @@ static int inner_child( return r; } - r = reset_uid_gid(); - if (r < 0) - return log_error_errno(r, "Couldn't become new root: %m"); - r = setup_boot_id(NULL); if (r < 0) return r; diff --git a/test/TEST-13-NSPAWN-SMOKE/Makefile b/test/TEST-13-NSPAWN-SMOKE/Makefile index 2ca5b12cf3..ff1470f852 100644 --- a/test/TEST-13-NSPAWN-SMOKE/Makefile +++ b/test/TEST-13-NSPAWN-SMOKE/Makefile @@ -1,7 +1,7 @@ -all: has-overflow +all: @make -s --no-print-directory -C ../.. all @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all -setup: has-overflow +setup: @make --no-print-directory -C ../.. all @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup clean: diff --git a/test/TEST-13-NSPAWN-SMOKE/has-overflow.c b/test/TEST-13-NSPAWN-SMOKE/has-overflow.c deleted file mode 100644 index 1b3331fad7..0000000000 --- a/test/TEST-13-NSPAWN-SMOKE/has-overflow.c +++ /dev/null @@ -1,143 +0,0 @@ -#define _GNU_SOURCE -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/mount.h> -#include <sched.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/wait.h> -#include <signal.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <limits.h> -#include <errno.h> -#include <grp.h> - -#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) - -struct child_args { - int pipe_fd[2]; /* Pipe used to synchronize parent and child */ -}; - -static void usage(char *pname) { - fprintf(stderr, "Options can be:\n"); - fprintf(stderr, "\t-M uid_map Specify UID map for user namespace\n"); - fprintf(stderr, "\t-G gid_map Specify GID map for user namespace\n"); - - exit(EXIT_FAILURE); -} - -static void update_map(char *mapping, char *map_file) { - int fd, j; - size_t map_len; - - map_len = strlen(mapping); - - fd = open(map_file, O_RDWR); - if (fd == -1) { - fprintf(stderr, "ERROR: open %s: %s\n", map_file, strerror(errno)); - exit(EXIT_FAILURE); - } - - if (write(fd, mapping, map_len) != map_len) { - fprintf(stderr, "ERROR: write %s: %s\n", map_file, strerror(errno)); - exit(EXIT_FAILURE); - } - - close(fd); -} - -static void proc_setgroups_write(pid_t child_pid, char *str) { - char setgroups_path[PATH_MAX]; - int fd; - - snprintf(setgroups_path, PATH_MAX, "/proc/%ld/setgroups", (long) child_pid); - - fd = open(setgroups_path, O_RDWR); - if (fd == -1) { - if (errno != ENOENT) - fprintf(stderr, "ERROR: open %s: %s\n", setgroups_path, strerror(errno)); - return; - } - - if (write(fd, str, strlen(str)) == -1) - fprintf(stderr, "ERROR: write %s: %s\n", setgroups_path, strerror(errno)); - - close(fd); -} - -static int child_func(void *arg) { - struct child_args *args = (struct child_args *) arg; - char ch; - - close(args->pipe_fd[1]); - if (read(args->pipe_fd[0], &ch, 1) != 0) { - fprintf(stderr, "Failure in child: read from pipe returned != 0\n"); - exit(EXIT_FAILURE); - } - - mount("tmpfs", "/tmp", "tmpfs", MS_MGC_VAL, "mode=777,uid=0,gid=0"); - if (mkdir("/tmp/hey", 0777) < 0) - exit(EXIT_FAILURE); - - exit(EXIT_SUCCESS); -} - -#define STACK_SIZE (1024 * 1024) - -static char child_stack[STACK_SIZE]; - -int main(int argc, char *argv[]) { - int flags, opt; - pid_t child_pid; - struct child_args args; - char *uid_map, *gid_map; - const int MAP_BUF_SIZE = 100; - char map_buf[MAP_BUF_SIZE]; - char map_path[PATH_MAX]; - int status; - - flags = 0; - gid_map = NULL; - uid_map = NULL; - while ((opt = getopt(argc, argv, "+M:G:")) != -1) { - switch (opt) { - case 'M': - uid_map = optarg; - break; - case 'G': - gid_map = optarg; - break; - default: - usage(argv[0]); - } - } - - if (!uid_map || !gid_map) - usage(argv[0]); - - flags |= CLONE_NEWNS; - flags |= CLONE_NEWUSER; - - if (pipe(args.pipe_fd) == -1) - errExit("pipe"); - - child_pid = clone(child_func, child_stack + STACK_SIZE, flags | SIGCHLD, &args); - if (child_pid == -1) - errExit("clone"); - - snprintf(map_path, PATH_MAX, "/proc/%ld/uid_map", (long) child_pid); - update_map(uid_map, map_path); - - proc_setgroups_write(child_pid, "allow"); - snprintf(map_path, PATH_MAX, "/proc/%ld/gid_map", (long) child_pid); - update_map(gid_map, map_path); - - close(args.pipe_fd[1]); - - if (waitpid(child_pid, &status, 0) == -1) - errExit("waitpid"); - - exit(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS ? EXIT_FAILURE : EXIT_SUCCESS); -} diff --git a/test/TEST-13-NSPAWN-SMOKE/test.sh b/test/TEST-13-NSPAWN-SMOKE/test.sh index dfc437c0ee..e6977a7f1c 100755 --- a/test/TEST-13-NSPAWN-SMOKE/test.sh +++ b/test/TEST-13-NSPAWN-SMOKE/test.sh @@ -40,7 +40,6 @@ test_setup() { setup_basic_environment dracut_install busybox chmod rmdir - dracut_install ./has-overflow cp create-busybox-container $initdir/ @@ -93,22 +92,8 @@ function run { /create-busybox-container "$_root" UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" systemd-nspawn --register=no -D "$_root" -b UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" systemd-nspawn --register=no -D "$_root" --private-network -b - - if ! UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" systemd-nspawn --register=no -D "$_root" -U -b; then - if [[ "$1" = "no" && "$2" = "yes" ]] && /has-overflow -M '0 1073283072 65536' -G '0 1073283072 65536'; then - printf "Failure expected, ignoring (see https://github.com/systemd/systemd/issues/4352)\n" >&2 - else - return 1 - fi - fi - - if ! UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" systemd-nspawn --register=no -D "$_root" --private-network -U -b; then - if [[ "$1" = "no" && "$2" = "yes" ]] && /has-overflow -M '0 1073283072 65536' -G '0 1073283072 65536'; then - printf "Failure expected, ignoring (see https://github.com/systemd/systemd/issues/4352)\n" >&2 - else - return 1 - fi - fi + UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" systemd-nspawn --register=no -D "$_root" -U -b + UNIFIED_CGROUP_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" systemd-nspawn --register=no -D "$_root" --private-network -U -b return 0 } |