diff options
Diffstat (limited to 'src/libsystemd-bus')
-rw-r--r-- | src/libsystemd-bus/bus-container.c | 149 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-container.h | 3 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.c | 69 |
3 files changed, 171 insertions, 50 deletions
diff --git a/src/libsystemd-bus/bus-container.c b/src/libsystemd-bus/bus-container.c index 33478c02de..5d31f5afa7 100644 --- a/src/libsystemd-bus/bus-container.c +++ b/src/libsystemd-bus/bus-container.c @@ -28,51 +28,23 @@ #include "bus-socket.h" #include "bus-container.h" -int bus_container_connect(sd_bus *b) { - _cleanup_free_ char *s = NULL, *ns = NULL, *root = NULL, *class = NULL; +int bus_container_connect_socket(sd_bus *b) { _cleanup_close_ int nsfd = -1, rootfd = -1; - char *p; - siginfo_t si; pid_t leader, child; + siginfo_t si; int r; assert(b); assert(b->input_fd < 0); assert(b->output_fd < 0); - p = strappenda("/run/systemd/machines/", b->machine); - r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); - if (r == -ENOENT) - return -EHOSTDOWN; + r = container_get_leader(b->machine, &leader); if (r < 0) return r; - if (!s) - return -EIO; - - if (!streq_ptr(class, "container")) - return -EIO; - r = parse_pid(s, &leader); + r = namespace_open(leader, &nsfd, &rootfd); if (r < 0) return r; - if (leader <= 1) - return -EIO; - - r = asprintf(&ns, "/proc/%lu/ns/mnt", (unsigned long) leader); - if (r < 0) - return -ENOMEM; - - nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (nsfd < 0) - return -errno; - - r = asprintf(&root, "/proc/%lu/root", (unsigned long) leader); - if (r < 0) - return -ENOMEM; - - rootfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); - if (rootfd < 0) - return -errno; b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (b->input_fd < 0) @@ -89,14 +61,9 @@ int bus_container_connect(sd_bus *b) { return -errno; if (child == 0) { - r = setns(nsfd, CLONE_NEWNS); - if (r < 0) - _exit(255); - - if (fchdir(rootfd) < 0) - _exit(255); - if (chroot(".") < 0) + r = namespace_enter(nsfd, rootfd); + if (r < 0) _exit(255); r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); @@ -107,7 +74,7 @@ int bus_container_connect(sd_bus *b) { _exit(255); } - _exit(0); + _exit(EXIT_SUCCESS); } r = wait_for_terminate(child, &si); @@ -120,8 +87,108 @@ int bus_container_connect(sd_bus *b) { if (si.si_status == 1) return 1; - if (si.si_status != 0) + if (si.si_status != EXIT_SUCCESS) return -EIO; return bus_socket_start_auth(b); } + +int bus_container_connect_kernel(sd_bus *b) { + _cleanup_close_pipe_ int pair[2] = { -1, -1 }; + _cleanup_close_ int nsfd = -1, rootfd = -1; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + pid_t leader, child; + siginfo_t si; + int r; + _cleanup_close_ int fd = -1; + + assert(b); + assert(b->input_fd < 0); + assert(b->output_fd < 0); + + r = container_get_leader(b->machine, &leader); + if (r < 0) + return r; + + r = namespace_open(leader, &nsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + close_nointr_nofail(pair[0]); + pair[0] = -1; + + r = namespace_enter(nsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + _exit(EXIT_FAILURE); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + close_nointr_nofail(pair[1]); + pair[1] = -1; + + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; + + fds = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + if (n_fds != 1) { + close_many(fds, n_fds); + return -EIO; + } + + fd = fds[0]; + } + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + + if (si.si_code != CLD_EXITED) + return -EIO; + + if (si.si_status != EXIT_SUCCESS) + return -EIO; + + b->input_fd = b->output_fd = fd; + fd = -1; + + return bus_kernel_take_fd(b); +} diff --git a/src/libsystemd-bus/bus-container.h b/src/libsystemd-bus/bus-container.h index 65f43ab4fd..c6f757a99b 100644 --- a/src/libsystemd-bus/bus-container.h +++ b/src/libsystemd-bus/bus-container.h @@ -23,4 +23,5 @@ #include "sd-bus.h" -int bus_container_connect(sd_bus *b); +int bus_container_connect_socket(sd_bus *b); +int bus_container_connect_kernel(sd_bus *b); diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 932bf226c5..4eaceeff04 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -740,7 +740,7 @@ static int parse_kernel_address(sd_bus *b, const char **p, char **guid) { return 0; } -static int parse_container_address(sd_bus *b, const char **p, char **guid) { +static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) { _cleanup_free_ char *machine = NULL; int r; @@ -782,6 +782,49 @@ static int parse_container_address(sd_bus *b, const char **p, char **guid) { return 0; } +static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid) { + _cleanup_free_ char *machine = NULL; + int r; + + assert(b); + assert(p); + assert(*p); + assert(guid); + + while (**p != 0 && **p != ';') { + r = parse_address_key(p, "guid", guid); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "machine", &machine); + if (r < 0) + return r; + else if (r > 0) + continue; + + skip_address_key(p); + } + + if (!machine) + return -EINVAL; + + if (!filename_is_safe(machine)) + return -EINVAL; + + free(b->machine); + b->machine = machine; + machine = NULL; + + free(b->kernel); + b->kernel = strdup("/dev/kdbus/0-system/bus"); + if (!b->kernel) + return -ENOMEM; + + return 0; +} + static void bus_reset_parsed_address(sd_bus *b) { assert(b); @@ -855,10 +898,18 @@ static int bus_parse_next_address(sd_bus *b) { return r; break; - } else if (startswith(a, "x-container:")) { + } else if (startswith(a, "x-container-unix:")) { + + a += 17; + r = parse_container_unix_address(b, &a, &guid); + if (r < 0) + return r; + + break; + } else if (startswith(a, "x-container-kernel:")) { - a += 12; - r = parse_container_address(b, &a, &guid); + a += 19; + r = parse_container_kernel_address(b, &a, &guid); if (r < 0) return r; @@ -892,10 +943,12 @@ static int bus_start_address(sd_bus *b) { if (b->exec_path) r = bus_socket_exec(b); + else if (b->machine && b->kernel) + r = bus_container_connect_kernel(b); + else if (b->machine && b->sockaddr.sa.sa_family != AF_UNSPEC) + r = bus_container_connect_socket(b); else if (b->kernel) r = bus_kernel_connect(b); - else if (b->machine) - r = bus_container_connect(b); else if (b->sockaddr.sa.sa_family != AF_UNSPEC) r = bus_socket_connect(b); else @@ -1144,9 +1197,9 @@ _public_ int sd_bus_open_system_container(const char *machine, sd_bus **ret) { return -ENOMEM; #ifdef ENABLE_KDBUS - p = strjoin("kernel:path=/dev/kdbus/ns/machine-", e, "/0-system/bus;x-container:machine=", e, NULL); + p = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL); #else - p = strjoin("x-container:machine=", e, NULL); + p = strjoin("x-container-unix:machine=", e, NULL); #endif if (!p) return -ENOMEM; |