Initialize user/group maps from the parent process
authorJagger <robert@swiecki.net>
Sun, 28 Feb 2016 01:34:43 +0000 (02:34 +0100)
committerJagger <robert@swiecki.net>
Sun, 28 Feb 2016 01:34:43 +0000 (02:34 +0100)
cmdline.c
contain.c
contain.h
subproc.c
util.c
util.h

index 0720c39991ff0f4f342b5310bd3d859787137b15..89d6a37900ea199c52804180572d5f870513746d 100644 (file)
--- a/cmdline.c
+++ b/cmdline.c
@@ -486,14 +486,14 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                        break;
                case 'E':
                        {
-                               struct charptr_t *p = util_malloc(sizeof(struct charptr_t));
+                               struct charptr_t *p = utilMalloc(sizeof(struct charptr_t));
                                p->val = optarg;
                                TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
                        }
                        break;
                case 'R':
                        {
-                               struct mounts_t *p = util_malloc(sizeof(struct mounts_t));
+                               struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                                p->src = optarg;
                                p->dst = cmdlineSplitStrByColon(optarg);
                                p->flags = MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY;
@@ -504,7 +504,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                        break;
                case 'B':
                        {
-                               struct mounts_t *p = util_malloc(sizeof(struct mounts_t));
+                               struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                                p->src = optarg;
                                p->dst = cmdlineSplitStrByColon(optarg);
                                p->flags = MS_BIND | MS_REC | MS_PRIVATE;
@@ -515,7 +515,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                        break;
                case 'T':
                        {
-                               struct mounts_t *p = util_malloc(sizeof(struct mounts_t));
+                               struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                                p->src = "/";
                                p->dst = optarg;
                                p->flags = 0;
@@ -559,7 +559,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
        }
 
        if (nsjconf->mount_proc == true) {
-               struct mounts_t *p = util_malloc(sizeof(struct mounts_t));
+               struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                p->src = "/proc";
                p->dst = "/proc";
                p->flags = 0;
@@ -568,7 +568,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                TAILQ_INSERT_HEAD(&nsjconf->mountpts, p, pointers);
        }
        {
-               struct mounts_t *p = util_malloc(sizeof(struct mounts_t));
+               struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
                p->src = nsjconf->chroot;
                p->dst = "/";
                p->flags = MS_BIND | MS_REC | MS_PRIVATE;
index e5a6501255d5f1abb59c4725a6ab3e3d357303dd..49503e96c8e67340bf5baf205409b40243fe303f 100644 (file)
--- a/contain.c
+++ b/contain.c
 #include <unistd.h>
 
 #include "log.h"
+#include "util.h"
 
-static bool containSetGroups(void)
+static bool containSetGroups(pid_t pid)
 {
-       int fd = open("/proc/self/setgroups", O_WRONLY | O_CLOEXEC);
-       if (fd == -1) {
-               /* Not present in all kernels */
-               PLOG_D("'/proc/self/setgroups' not present in this kernel?");
-               return true;
-       }
+       char fname[PATH_MAX];
+       snprintf(fname, sizeof(fname), "/proc/%d/setgroups", pid);
        const char *denystr = "deny";
-       if (write(fd, denystr, strlen(denystr)) == -1) {
-               PLOG_E("write('/proc/self/setgroups', '%s') failed", denystr);
-               close(fd);
+       if (utilWriteBufToFile(fname, denystr, strlen(denystr), O_WRONLY) == false) {
+               LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, denystr);
                return false;
        }
-       close(fd);
        return true;
 }
 
-static bool containUidGidMap(struct nsjconf_t *nsjconf)
+static bool containUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
 {
        if (nsjconf->clone_newuser == false) {
                return true;
        }
 
-       sleep(10);
-       return true;
+       char fname[PATH_MAX];
+       char map[128];
 
-       int fd;
-       char map[64];
-       if ((fd = open("/proc/self/uid_map", O_WRONLY | O_CLOEXEC)) == -1) {
-               PLOG_E("open('/proc/self/uid_map', O_WRONLY | O_CLOEXEC)");
-               return false;
-       }
+       snprintf(fname, sizeof(fname), "/proc/%d/uid_map", pid);
        snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_uid,
                 (unsigned long)nsjconf->outside_uid);
-       LOG_D("Writing '%s' to /proc/self/uid_map", map);
-       if (write(fd, map, strlen(map)) == -1) {
-               PLOG_E("write('/proc/self/uid_map', %d, '%s')", fd, map);
-               close(fd);
+       LOG_D("Writing '%s' to '%s'", map, fname);
+       if (utilWriteBufToFile(fname, map, strlen(map), O_WRONLY) == false) {
+               LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, map);
                return false;
        }
-       close(fd);
 
-       if ((fd = open("/proc/self/gid_map", O_WRONLY | O_CLOEXEC)) == -1) {
-               PLOG_E("open('/proc/self/gid_map', O_WRONLY | O_CLOEXEC)");
-               return false;
-       }
+       snprintf(fname, sizeof(fname), "/proc/%d/gid_map", pid);
        snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_gid,
                 (unsigned long)nsjconf->outside_gid);
-       LOG_D("Writing '%s' to /proc/self/gid_map", map);
-       if (write(fd, map, strlen(map)) == -1) {
-               PLOG_E("write('/proc/self/gid_map', %d, '%s')", fd, map);
-               close(fd);
+       LOG_D("Writing '%s' to '%s'", map, fname);
+       if (utilWriteBufToFile(fname, map, strlen(map), O_WRONLY) == false) {
+               LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, map);
                return false;
        }
-       close(fd);
        return true;
 }
 
-bool containInitUserNs(struct nsjconf_t * nsjconf)
+bool containInitUserNs(struct nsjconf_t * nsjconf, pid_t pid)
 {
-       if (containSetGroups() == false) {
+       if (containSetGroups(pid) == false) {
                return false;
        }
-       if (containUidGidMap(nsjconf) == false) {
+       if (containUidGidMap(nsjconf, pid) == false) {
                return false;
        }
        return true;
index 46976969cc6b1a7d80173278b4597915a76be9ac..d288f07c23ce88b2dac1306079b0cdb906af2417 100644 (file)
--- a/contain.h
+++ b/contain.h
@@ -26,7 +26,7 @@
 
 #include "common.h"
 
-bool containInitUserNs(struct nsjconf_t *nsjconf);
+bool containInitUserNs(struct nsjconf_t *nsjconf, pid_t pid);
 bool containDropPrivs(struct nsjconf_t *nsjconf);
 bool containPrepareEnv(struct nsjconf_t *nsjconf);
 bool containMountFS(struct nsjconf_t *nsjconf);
index ac2e4616673007a1205cd2b1fa2a4430803d2c6d..b0776fd02c7aba882c29b85cc70d5d228a791d12 100644 (file)
--- a/subproc.c
+++ b/subproc.c
 #include "sandbox.h"
 #include "util.h"
 
+const char subprocDoneChar = 'D';
+
 static int subprocNewProc(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int fd_err, int pipefd)
 {
-       if (containInitUserNs(nsjconf) == false) {
+       if (containSetupFD(nsjconf, fd_in, fd_out, fd_err, pipefd) == false) {
                exit(1);
        }
-       if (containPrepareEnv(nsjconf) == false) {
+       char doneChar;
+       if (utilReadFromFd(pipefd, &doneChar, sizeof(doneChar)) != sizeof(doneChar)) {
                exit(1);
        }
-       if (containSetupFD(nsjconf, fd_in, fd_out, fd_err, pipefd) == false) {
+       if (doneChar != subprocDoneChar) {
+               exit(1);
+       }
+       if (containPrepareEnv(nsjconf) == false) {
                exit(1);
        }
        if (containMountFS(nsjconf) == false) {
@@ -97,7 +103,7 @@ static int subprocNewProc(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int
 
 static void subprocAdd(struct nsjconf_t *nsjconf, pid_t pid, int sock)
 {
-       struct pids_t *p = util_malloc(sizeof(struct pids_t));
+       struct pids_t *p = utilMalloc(sizeof(struct pids_t));
        p->pid = pid;
        p->start = time(NULL);
        netConnToText(sock, true /* remote */ , p->remote_txt, sizeof(p->remote_txt),
@@ -231,41 +237,49 @@ void subprocRunChild(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int fd_er
        flags |= SIGCHLD;
        LOG_D("Creating new process with clone flags: %#x", flags);
 
-       int pipefd[2];
-       if (pipe2(pipefd, O_CLOEXEC) == -1) {
-               PLOG_E("pipe2(pipefd, O_CLOEXEC) failed");
+       int sv[2];
+       if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) == -1) {
+               PLOG_E("socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC) failed");
                return;
        }
 
        pid_t pid = syscall(__NR_clone, (uintptr_t) flags, NULL, NULL, NULL, (uintptr_t) 0);
        if (pid == 0) {
-               subprocNewProc(nsjconf, fd_in, fd_out, fd_err, pipefd[1]);
+               close(sv[1]);
+               subprocNewProc(nsjconf, fd_in, fd_out, fd_err, sv[0]);
        }
+       close(sv[0]);
 
        if (pid == -1) {
                PLOG_E("clone(flags=%#x) failed. You probably need root privileges if your system "
                       "doesn't support CLONE_NEWUSER. Alternatively, you might want to recompile your "
                       "kernel with support for namespaces or check the setting of the "
                       "kernel.unprivileged_userns_clone sysctl", flags);
+               close(sv[1]);
                return;
        }
 
        if (netCloneMacVtapAndNS(nsjconf, pid) == false) {
                LOG_E("Couldn't create and put MACVTAP interface into NS of PID '%d'", pid);
        }
+       if (containInitUserNs(nsjconf, pid) == false) {
+               LOG_E("Couldn't initialize user namespaces for pid %d", pid);
+       }
+       if (utilWriteToFd(sv[1], &subprocDoneChar, sizeof(subprocDoneChar)) == false) {
+               LOG_E("Couldn't signal the new process via a socketpair");
+       }
 
        char cs_addr[64];
        netConnToText(fd_in, true /* remote */ , cs_addr, sizeof(cs_addr), NULL);
        LOG_I("PID: %d about to execute '%s' for %s", pid, nsjconf->argv[0], cs_addr);
 
        char log_buf[4096];
-       close(pipefd[1]);
        ssize_t sz;
-       while ((sz = read(pipefd[0], log_buf, sizeof(log_buf) - 1)) > 0) {
+       while ((sz = read(sv[1], log_buf, sizeof(log_buf) - 1)) > 0) {
                log_buf[sz] = '\0';
                logDirectlyToFD(log_buf);
        }
-       close(pipefd[0]);
+       close(sv[1]);
 
        subprocAdd(nsjconf, pid, fd_in);
 }
diff --git a/util.c b/util.c
index 4c7e965ce22fb7cf3926e910574bfea67b845e6d..fca97f6fa79370eeaecdf379e375a59708c9cd08 100644 (file)
--- a/util.c
+++ b/util.c
 
 #include "util.h"
 
+#include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "log.h"
 
-void *util_malloc(size_t sz)
+void *utilMalloc(size_t sz)
 {
        void *ret = malloc(sz);
        if (ret == NULL) {
@@ -33,3 +38,60 @@ void *util_malloc(size_t sz)
        }
        return ret;
 }
+
+ssize_t utilReadFromFd(int fd, void *buf, size_t len)
+{
+       uint8_t *charbuf = (uint8_t *) buf;
+
+       size_t readSz = 0;
+       while (readSz < len) {
+               ssize_t sz = read(fd, &charbuf[readSz], len - readSz);
+               if (sz < 0 && errno == EINTR)
+                       continue;
+
+               if (sz <= 0)
+                       break;
+
+               readSz += sz;
+       }
+       return readSz;
+}
+
+ssize_t utilWriteToFd(int fd, const void *buf, size_t len)
+{
+       const uint8_t *charbuf = (const uint8_t *)buf;
+
+       size_t writtenSz = 0;
+       while (writtenSz < len) {
+               ssize_t sz = write(fd, &charbuf[writtenSz], len - writtenSz);
+               if (sz < 0 && errno == EINTR)
+                       continue;
+
+               if (sz < 0)
+                       return false;
+
+               writtenSz += sz;
+       }
+       return true;
+}
+
+bool utilWriteBufToFile(char *filename, const void *buf, size_t len, int open_flags)
+{
+       int fd = open(filename, open_flags, 0644);
+       if (fd == -1) {
+               PLOG_E("Couldn't open '%s' for R/O", filename);
+               return false;
+       }
+
+       if (utilWriteToFd(fd, buf, len) == false) {
+               PLOG_E("Couldn't write '%zu' bytes to file '%s' (fd='%d')", len, filename, fd);
+               close(fd);
+               unlink(filename);
+               return false;
+       }
+       close(fd);
+
+       LOG_D("Written '%zu' bytes to '%s'", len, filename);
+
+       return true;
+}
diff --git a/util.h b/util.h
index a38fcb79dc2760eacd0388d803ecc806651762f5..e1edde7e523ba7d609af42c6a58982170eb9b9a2 100644 (file)
--- a/util.h
+++ b/util.h
 #ifndef _UTIL_H
 #define _UTIL_H
 
+#include <stdbool.h>
 #include <stdlib.h>
 
-void *util_malloc(size_t sz);
+void *utilMalloc(size_t sz);
+ssize_t utilWriteToFd(int fd, const void *buf, size_t len);
+ssize_t utilReadFromFd(int fd, void *buf, size_t len);
+bool utilWriteBufToFile(char *filename, const void *buf, size_t len, int open_flags);
 
 #endif                         /* _UTIL_H */