chiark / gitweb /
loopback-setup: correctly set flags and scope for ipv6 address
[elogind.git] / src / libsystemd-bus / bus-container.c
index 5d31f5afa72466213db094562fb14c08dafd4258..02886c4ded1ab47a6bd9f1aa2d31e204aa3d0750 100644 (file)
@@ -29,7 +29,7 @@
 #include "bus-container.h"
 
 int bus_container_connect_socket(sd_bus *b) {
-        _cleanup_close_ int nsfd = -1, rootfd = -1;
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
         pid_t leader, child;
         siginfo_t si;
         int r;
@@ -42,7 +42,7 @@ int bus_container_connect_socket(sd_bus *b) {
         if (r < 0)
                 return r;
 
-        r = namespace_open(leader, &nsfd, &rootfd);
+        r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd);
         if (r < 0)
                 return r;
 
@@ -61,20 +61,44 @@ int bus_container_connect_socket(sd_bus *b) {
                 return -errno;
 
         if (child == 0) {
+                pid_t grandchild;
 
-                r = namespace_enter(nsfd, rootfd);
+                r = namespace_enter(pidnsfd, mntnsfd, rootfd);
                 if (r < 0)
                         _exit(255);
 
-                r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
-                if (r < 0) {
-                        if (errno == EINPROGRESS)
-                                _exit(1);
+                /* 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 */
 
+                grandchild = fork();
+                if (grandchild < 0)
                         _exit(255);
+
+                if (grandchild == 0) {
+
+                        r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
+                        if (r < 0) {
+                                if (errno == EINPROGRESS)
+                                        _exit(1);
+
+                                _exit(255);
+                        }
+
+                        _exit(EXIT_SUCCESS);
                 }
 
-                _exit(EXIT_SUCCESS);
+                r = wait_for_terminate(grandchild, &si);
+                if (r < 0)
+                        _exit(255);
+
+                if (si.si_code != CLD_EXITED)
+                        _exit(255);
+
+                _exit(si.si_status);
         }
 
         r = wait_for_terminate(child, &si);
@@ -95,7 +119,7 @@ int bus_container_connect_socket(sd_bus *b) {
 
 int bus_container_connect_kernel(sd_bus *b) {
         _cleanup_close_pipe_ int pair[2] = { -1, -1 };
-        _cleanup_close_ int nsfd = -1, rootfd = -1;
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
         union {
                 struct cmsghdr cmsghdr;
                 uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -118,7 +142,7 @@ int bus_container_connect_kernel(sd_bus *b) {
         if (r < 0)
                 return r;
 
-        r = namespace_open(leader, &nsfd, &rootfd);
+        r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd);
         if (r < 0)
                 return r;
 
@@ -130,29 +154,54 @@ int bus_container_connect_kernel(sd_bus *b) {
                 return -errno;
 
         if (child == 0) {
+                pid_t grandchild;
+
                 close_nointr_nofail(pair[0]);
                 pair[0] = -1;
 
-                r = namespace_enter(nsfd, rootfd);
+                r = namespace_enter(pidnsfd, mntnsfd, rootfd);
                 if (r < 0)
                         _exit(EXIT_FAILURE);
 
-                fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
-                if (fd < 0)
+                /* 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 kdbus only sees the credentials
+                 * of this process which comes from within the
+                 * container, and not outside of it */
+
+                grandchild = fork();
+                if (grandchild < 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));
+                if (grandchild == 0) {
+
+                        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;
 
-                mh.msg_controllen = cmsg->cmsg_len;
+                        if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
+                                _exit(EXIT_FAILURE);
+
+                        _exit(EXIT_SUCCESS);
+                }
+
+                r = wait_for_terminate(grandchild, &si);
+                if (r < 0)
+                        _exit(EXIT_FAILURE);
 
-                if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
+                if (si.si_code != CLD_EXITED)
                         _exit(EXIT_FAILURE);
 
-                _exit(EXIT_SUCCESS);
+                _exit(si.si_status);
         }
 
         close_nointr_nofail(pair[1]);