diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-11-14 12:47:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-14 12:47:56 +0100 |
commit | b5be61d1ed6d29fa811830654854267d723567ce (patch) | |
tree | 12ce564f4a5bc4d722a92ff68d2d2e11e664d5c3 | |
parent | eff162bf963f1fd52e8b32d04274f8f5f228f94c (diff) | |
parent | 1edcb6a91ce459aed9abdf63b2724745a7cf8f45 (diff) | |
download | systemd-b5be61d1ed6d29fa811830654854267d723567ce.tar.gz |
Merge pull request #10747 from poettering/machinectl-list-fix
properly acquire os-release file from containers
-rw-r--r-- | src/basic/process-util.c | 54 | ||||
-rw-r--r-- | src/basic/process-util.h | 2 | ||||
-rw-r--r-- | src/basic/terminal-util.c | 18 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-container.c | 42 | ||||
-rw-r--r-- | src/machine/machine-dbus.c | 32 | ||||
-rw-r--r-- | src/shared/logs-show.c | 9 |
6 files changed, 86 insertions, 71 deletions
diff --git a/src/basic/process-util.c b/src/basic/process-util.c index b2aab853e2..572d7eb38d 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1409,6 +1409,60 @@ int safe_fork_full( return 0; } +int namespace_fork( + const char *outer_name, + const char *inner_name, + const int except_fds[], + size_t n_except_fds, + ForkFlags flags, + int pidns_fd, + int mntns_fd, + int netns_fd, + int userns_fd, + int root_fd, + pid_t *ret_pid) { + + int r; + + /* This is much like safe_fork(), but forks twice, and joins the specified namespaces in the middle + * process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that + * /proc/self/fd works correctly. */ + + r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid); + if (r < 0) + return r; + if (r == 0) { + pid_t pid; + + /* Child */ + + r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd); + if (r < 0) { + log_full_errno(FLAGS_SET(flags, FORK_LOG) ? LOG_ERR : LOG_DEBUG, r, "Failed to join namespace: %m"); + _exit(EXIT_FAILURE); + } + + /* We mask a few flags here that either make no sense for the grandchild, or that we don't have to do again */ + r = safe_fork_full(inner_name, except_fds, n_except_fds, flags & ~(FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NULL_STDIO), &pid); + if (r < 0) + _exit(EXIT_FAILURE); + if (r == 0) { + /* Child */ + if (ret_pid) + *ret_pid = pid; + return 0; + } + + r = wait_for_terminate_and_check(inner_name, pid, FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0); + if (r < 0) + _exit(EXIT_FAILURE); + + _exit(r); + } + + return 1; +} + int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) { bool stdout_is_tty, stderr_is_tty; size_t n, i; diff --git a/src/basic/process-util.h b/src/basic/process-util.h index ca4e4401a9..af47513fab 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -159,6 +159,8 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) { return safe_fork_full(name, NULL, 0, flags, ret_pid); } +int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid); + int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...) _sentinel_; int set_oom_score_adjust(int value); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index ea0ba442ff..41789598f7 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1095,7 +1095,8 @@ int openpt_in_namespace(pid_t pid, int flags) { if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) return -errno; - r = safe_fork("(sd-openpt)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + r = namespace_fork("(sd-openptns)", "(sd-openpt)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + pidnsfd, mntnsfd, -1, usernsfd, rootfd, &child); if (r < 0) return r; if (r == 0) { @@ -1103,10 +1104,6 @@ int openpt_in_namespace(pid_t pid, int flags) { pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); - if (r < 0) - _exit(EXIT_FAILURE); - master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC); if (master < 0) _exit(EXIT_FAILURE); @@ -1122,7 +1119,7 @@ int openpt_in_namespace(pid_t pid, int flags) { pair[1] = safe_close(pair[1]); - r = wait_for_terminate_and_check("(sd-openpt)", child, 0); + r = wait_for_terminate_and_check("(sd-openptns)", child, 0); if (r < 0) return r; if (r != EXIT_SUCCESS) @@ -1144,7 +1141,8 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) return -errno; - r = safe_fork("(sd-terminal)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + r = namespace_fork("(sd-terminalns)", "(sd-terminal)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + pidnsfd, mntnsfd, -1, usernsfd, rootfd, &child); if (r < 0) return r; if (r == 0) { @@ -1152,10 +1150,6 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); - if (r < 0) - _exit(EXIT_FAILURE); - master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC); if (master < 0) _exit(EXIT_FAILURE); @@ -1168,7 +1162,7 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { pair[1] = safe_close(pair[1]); - r = wait_for_terminate_and_check("(sd-terminal)", child, 0); + r = wait_for_terminate_and_check("(sd-terminalns)", child, 0); if (r < 0) return r; if (r != EXIT_SUCCESS) diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 38023087a3..2cfeefc2c3 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -45,51 +45,27 @@ int bus_container_connect_socket(sd_bus *b) { if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) return -errno; - r = safe_fork("(sd-buscntr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + r = namespace_fork("(sd-buscntrns)", "(sd-buscntr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + pidnsfd, mntnsfd, -1, usernsfd, rootfd, &child); if (r < 0) return r; if (r == 0) { - pid_t grandchild; - pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); - if (r < 0) - _exit(EXIT_FAILURE); - - /* We just changed PID namespace, however it will only - * take effect on the children we now fork. Hence, - * let's fork another time, and connect from this - * grandchild, so that SO_PEERCRED of our connection - * comes from a process from within the container, and - * not outside of it */ - - r = safe_fork("(sd-buscntr2)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &grandchild); - if (r < 0) + r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); + if (r < 0) { + /* Try to send error up */ + error_buf = errno; + (void) write(pair[1], &error_buf, sizeof(error_buf)); _exit(EXIT_FAILURE); - if (r == 0) { - - r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); - if (r < 0) { - /* Try to send error up */ - error_buf = errno; - (void) write(pair[1], &error_buf, sizeof(error_buf)); - _exit(EXIT_FAILURE); - } - - _exit(EXIT_SUCCESS); } - r = wait_for_terminate_and_check("(sd-buscntr2)", grandchild, 0); - if (r < 0) - _exit(EXIT_FAILURE); - - _exit(r); + _exit(EXIT_SUCCESS); } pair[1] = safe_close(pair[1]); - r = wait_for_terminate_and_check("(sd-buscntr)", child, 0); + r = wait_for_terminate_and_check("(sd-buscntrns)", child, 0); if (r < 0) return r; if (r != EXIT_SUCCESS) diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 4f4d780db0..2f9f587973 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -207,7 +207,8 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) return -errno; - r = safe_fork("(sd-addr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + r = namespace_fork("(sd-addrns)", "(sd-addr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + -1, -1, netns_fd, -1, -1, &child); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); if (r == 0) { @@ -217,10 +218,6 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd pair[0] = safe_close(pair[0]); - r = namespace_enter(-1, -1, netns_fd, -1, -1); - if (r < 0) - _exit(EXIT_FAILURE); - n = local_addresses(NULL, 0, AF_UNSPEC, &addresses); if (n < 0) _exit(EXIT_FAILURE); @@ -294,7 +291,7 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd return r; } - r = wait_for_terminate_and_check("(sd-addr)", child, 0); + r = wait_for_terminate_and_check("(sd-addrns)", child, 0); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); if (r != EXIT_SUCCESS) @@ -333,19 +330,21 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s break; case MACHINE_CONTAINER: { - _cleanup_close_ int mntns_fd = -1, root_fd = -1; + _cleanup_close_ int mntns_fd = -1, root_fd = -1, pidns_fd = -1; _cleanup_close_pair_ int pair[2] = { -1, -1 }; _cleanup_fclose_ FILE *f = NULL; pid_t child; - r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd); + r = namespace_open(m->leader, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd); if (r < 0) return r; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) return -errno; - r = safe_fork("(sd-osrel)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + r = namespace_fork("(sd-osrelns)", "(sd-osrel)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + pidns_fd, mntns_fd, -1, -1, root_fd, + &child); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); if (r == 0) { @@ -353,10 +352,6 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s pair[0] = safe_close(pair[0]); - r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); - if (r < 0) - _exit(EXIT_FAILURE); - r = open_os_release(NULL, NULL, &fd); if (r == -ENOENT) _exit(EXIT_NOT_FOUND); @@ -382,7 +377,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s if (r < 0) return r; - r = wait_for_terminate_and_check("(sd-osrel)", child, 0); + r = wait_for_terminate_and_check("(sd-osrelns)", child, 0); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); if (r == EXIT_NOT_FOUND) @@ -1239,7 +1234,8 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) return -errno; - r = safe_fork("(sd-openroot)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + r = namespace_fork("(sd-openrootns)", "(sd-openroot)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + -1, mntns_fd, -1, -1, root_fd, &child); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); if (r == 0) { @@ -1247,10 +1243,6 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda pair[0] = safe_close(pair[0]); - r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); - if (r < 0) - _exit(EXIT_FAILURE); - dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (dfd < 0) _exit(EXIT_FAILURE); @@ -1265,7 +1257,7 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda pair[1] = safe_close(pair[1]); - r = wait_for_terminate_and_check("(sd-openroot)", child, 0); + r = wait_for_terminate_and_check("(sd-openrootns)", child, 0); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); if (r != EXIT_SUCCESS) diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 79e47b8417..2d53307203 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -1342,7 +1342,8 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) return -errno; - r = safe_fork("(sd-bootid)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); + r = namespace_fork("(sd-bootidns)", "(sd-bootid)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + pidnsfd, mntnsfd, -1, -1, rootfd, &child); if (r < 0) return r; if (r == 0) { @@ -1350,10 +1351,6 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, -1, rootfd); - if (r < 0) - _exit(EXIT_FAILURE); - fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) _exit(EXIT_FAILURE); @@ -1372,7 +1369,7 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { pair[1] = safe_close(pair[1]); - r = wait_for_terminate_and_check("(sd-bootid)", child, 0); + r = wait_for_terminate_and_check("(sd-bootidns)", child, 0); if (r < 0) return r; if (r != EXIT_SUCCESS) |