X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibelogind%2Fsd-bus%2Fbus-container.c;h=7da6ba990382f4da5e86a8545920d50f51a306ef;hb=94c5f7fa9e34517edad75cd63d71dd459ec4f133;hp=fa7a207448806f8e5cc3e5efd2a3a5217d05a7e3;hpb=0c92f823aefd539d59fe78f2ba0e75b80ef7f906;p=elogind.git
diff --git a/src/libelogind/sd-bus/bus-container.c b/src/libelogind/sd-bus/bus-container.c
index fa7a20744..7da6ba990 100644
--- a/src/libelogind/sd-bus/bus-container.c
+++ b/src/libelogind/sd-bus/bus-container.c
@@ -19,20 +19,23 @@
along with systemd; If not, see .
***/
-#include
#include
+#include
-#include "util.h"
-#include "process-util.h"
+#include "bus-container.h"
#include "bus-internal.h"
#include "bus-socket.h"
-#include "bus-container.h"
+#include "fd-util.h"
+#include "process-util.h"
+#include "util.h"
int bus_container_connect_socket(sd_bus *b) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
pid_t child;
siginfo_t si;
- int r;
+ int r, error_buf = 0;
+ ssize_t n;
assert(b);
assert(b->input_fd < 0);
@@ -45,7 +48,7 @@ int bus_container_connect_socket(sd_bus *b) {
return r;
}
- r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
@@ -57,6 +60,9 @@ int bus_container_connect_socket(sd_bus *b) {
bus_socket_setup(b);
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
+ return -errno;
+
child = fork();
if (child < 0)
return -errno;
@@ -64,9 +70,11 @@ int bus_container_connect_socket(sd_bus *b) {
if (child == 0) {
pid_t grandchild;
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
- _exit(255);
+ _exit(EXIT_FAILURE);
/* We just changed PID namespace, however it will only
* take effect on the children we now fork. Hence,
@@ -77,16 +85,16 @@ int bus_container_connect_socket(sd_bus *b) {
grandchild = fork();
if (grandchild < 0)
- _exit(255);
+ _exit(EXIT_FAILURE);
if (grandchild == 0) {
r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
if (r < 0) {
- if (errno == EINPROGRESS)
- _exit(1);
-
- _exit(255);
+ /* Try to send error up */
+ error_buf = errno;
+ (void) write(pair[1], &error_buf, sizeof(error_buf));
+ _exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
@@ -94,24 +102,41 @@ int bus_container_connect_socket(sd_bus *b) {
r = wait_for_terminate(grandchild, &si);
if (r < 0)
- _exit(255);
+ _exit(EXIT_FAILURE);
if (si.si_code != CLD_EXITED)
- _exit(255);
+ _exit(EXIT_FAILURE);
_exit(si.si_status);
}
+ pair[1] = safe_close(pair[1]);
+
r = wait_for_terminate(child, &si);
if (r < 0)
return r;
+ n = read(pair[0], &error_buf, sizeof(error_buf));
+ if (n < 0)
+ return -errno;
+
+ if (n > 0) {
+ if (n != sizeof(error_buf))
+ return -EIO;
+
+ if (error_buf < 0)
+ return -EIO;
+
+ if (error_buf == EINPROGRESS)
+ return 1;
+
+ if (error_buf > 0)
+ return -error_buf;
+ }
+
if (si.si_code != CLD_EXITED)
return -EIO;
- if (si.si_status == 1)
- return 1;
-
if (si.si_status != EXIT_SUCCESS)
return -EIO;
@@ -120,20 +145,27 @@ int bus_container_connect_socket(sd_bus *b) {
int bus_container_connect_kernel(sd_bus *b) {
_cleanup_close_pair_ int pair[2] = { -1, -1 };
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
} control = {};
+ int error_buf = 0;
+ struct iovec iov = {
+ .iov_base = &error_buf,
+ .iov_len = sizeof(error_buf),
+ };
struct msghdr mh = {
.msg_control = &control,
.msg_controllen = sizeof(control),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
};
struct cmsghdr *cmsg;
pid_t child;
siginfo_t si;
- int r;
- _cleanup_close_ int fd = -1;
+ int r, fd = -1;
+ ssize_t n;
assert(b);
assert(b->input_fd < 0);
@@ -146,11 +178,11 @@ int bus_container_connect_kernel(sd_bus *b) {
return r;
}
- r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
return -errno;
child = fork();
@@ -162,7 +194,7 @@ int bus_container_connect_kernel(sd_bus *b) {
pair[0] = safe_close(pair[0]);
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
@@ -178,20 +210,16 @@ int bus_container_connect_kernel(sd_bus *b) {
_exit(EXIT_FAILURE);
if (grandchild == 0) {
-
fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
+ if (fd < 0) {
+ /* Try to send error up */
+ error_buf = errno;
+ (void) write(pair[1], &error_buf, sizeof(error_buf));
_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)
+ r = send_one_fd(pair[1], fd, 0);
+ if (r < 0)
_exit(EXIT_FAILURE);
_exit(EXIT_SUCCESS);
@@ -213,20 +241,17 @@ int bus_container_connect_kernel(sd_bus *b) {
if (r < 0)
return r;
- if (si.si_code != CLD_EXITED)
- return -EIO;
-
- if (si.si_status != EXIT_SUCCESS)
- return -EIO;
-
- if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
+ n = recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
+ if (n < 0)
return -errno;
- CMSG_FOREACH(cmsg, &mh)
+ CMSG_FOREACH(cmsg, &mh) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
int *fds;
unsigned n_fds;
+ assert(fd < 0);
+
fds = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
@@ -237,9 +262,18 @@ int bus_container_connect_kernel(sd_bus *b) {
fd = fds[0];
}
+ }
+
+ /* If there's an fd passed, we are good. */
+ if (fd >= 0) {
+ b->input_fd = b->output_fd = fd;
+ return bus_kernel_take_fd(b);
+ }
- b->input_fd = b->output_fd = fd;
- fd = -1;
+ /* If there's an error passed, use it */
+ if (n == sizeof(error_buf) && error_buf > 0)
+ return -error_buf;
- return bus_kernel_take_fd(b);
+ /* Otherwise, we have no clue */
+ return -EIO;
}