Implement --pass_fd
authorJagger <robert@swiecki.net>
Fri, 17 Jun 2016 22:46:57 +0000 (00:46 +0200)
committerJagger <robert@swiecki.net>
Fri, 17 Jun 2016 22:46:57 +0000 (00:46 +0200)
Makefile
cmdline.c
common.h
contain.c

index 841352bdb2acb751763e9b24dc20550ee3db2b45..b49d29d947742adef8cfda50ffd9c67fc708562c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -66,10 +66,11 @@ indent:
 
 nsjail.o: nsjail.h common.h cmdline.h log.h net.h subproc.h
 cmdline.o: cmdline.h common.h log.h util.h
-contain.o: contain.h common.h log.h mount.h net.h util.h uts.h
+contain.o: contain.h common.h log.h mount.h net.h pid.h util.h uts.h
 log.o: log.h common.h
 mount.o: mount.h common.h log.h
 net.o: net.h common.h log.h
+pid.o: pid.h common.h log.h
 sandbox.o: sandbox.h common.h log.h seccomp/bpf-helper.h
 subproc.o: subproc.h common.h contain.h log.h net.h sandbox.h user.h util.h
 user.o: user.h common.h log.h util.h
index 0cb596c78ca069cdca513990e8026f34bac664b9..23a2cd592bd15b043f6ca1c0a6ff68d7a72b631c 100644 (file)
--- a/cmdline.c
+++ b/cmdline.c
@@ -301,12 +301,24 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
        TAILQ_INIT(&nsjconf->envs);
        TAILQ_INIT(&nsjconf->pids);
        TAILQ_INIT(&nsjconf->mountpts);
+       TAILQ_INIT(&nsjconf->open_fds);
 
        char *user = NULL;
        char *group = NULL;
        const char *logfile = NULL;
        static char cmdlineTmpfsSz[PATH_MAX] = "size=4194304";
 
+       struct fds_t *f;
+       f = utilMalloc(sizeof(struct fds_t));
+       f->fd = STDIN_FILENO;
+       TAILQ_INSERT_HEAD(&nsjconf->open_fds, f, pointers);
+       f = utilMalloc(sizeof(struct fds_t));
+       f->fd = STDOUT_FILENO;
+       TAILQ_INSERT_HEAD(&nsjconf->open_fds, f, pointers);
+       f = utilMalloc(sizeof(struct fds_t));
+       f->fd = STDERR_FILENO;
+       TAILQ_INSERT_HEAD(&nsjconf->open_fds, f, pointers);
+
         /*  *INDENT-OFF* */
        struct custom_option custom_opts[] = {
                {{"help", no_argument, NULL, 'h'}, "Help plz.."},
@@ -335,6 +347,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                {{"silent", no_argument, NULL, 0x0502}, "Redirect child's fd:0/1/2 to /dev/null"},
                {{"disable_sandbox", no_argument, NULL, 0x0503}, "Don't enable the seccomp-bpf sandboxing"},
                {{"skip_setsid", no_argument, NULL, 0x0504}, "Don't call setsid(), allows for terminal signal handling in the sandboxed process"},
+               {{"pass_fd", required_argument, NULL, 0x0505}, "Don't close this FD before executing child (can be specified multiple times (by default: 0/1/2 are kept open)"},
                {{"rlimit_as", required_argument, NULL, 0x0201}, "RLIMIT_AS in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 512)"},
                {{"rlimit_core", required_argument, NULL, 0x0202}, "RLIMIT_CORE in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 0)"},
                {{"rlimit_cpu", required_argument, NULL, 0x0203}, "RLIMIT_CPU, 'max' for RLIM_INFINITY, 'def' for the current value (default: 600)"},
@@ -492,6 +505,14 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
                case 0x0504:
                        nsjconf->skip_setsid = true;
                        break;
+               case 0x0505:
+                       {
+                               struct fds_t *f;
+                               f = utilMalloc(sizeof(struct fds_t));
+                               f->fd = (int)strtol(optarg, NULL, 0);
+                               TAILQ_INSERT_HEAD(&nsjconf->open_fds, f, pointers);
+                       }
+                       break;
                case 0x0601:
                        nsjconf->is_root_rw = true;
                        break;
index 992fc594c07c817870503628e451d25b5e8e3248..78998a7fdd078352c66abdd85e1389f98b6137e4 100644 (file)
--- a/common.h
+++ b/common.h
@@ -69,6 +69,11 @@ struct mounts_t {
         TAILQ_ENTRY(mounts_t) pointers;
 };
 
+struct fds_t {
+       int fd;
+        TAILQ_ENTRY(fds_t) pointers;
+};
+
 enum mode_t {
        MODE_LISTEN_TCP = 0,
        MODE_STANDALONE_ONCE,
@@ -127,6 +132,7 @@ struct nsjconf_t {
         TAILQ_HEAD(envlist, charptr_t) envs;
         TAILQ_HEAD(pidslist, pids_t) pids;
         TAILQ_HEAD(mountptslist, mounts_t) mountpts;
+        TAILQ_HEAD(fdslistt, fds_t) open_fds;
 };
 
 #endif                         /* NS_COMMON_H */
index ff56777d8116d792cbae011c8029963fb4d0cf54..beeb67d2ce6ebb052858c235c27315ef0522fdba 100644 (file)
--- a/contain.c
+++ b/contain.c
@@ -186,23 +186,38 @@ static bool containSetLimits(struct nsjconf_t *nsjconf)
        return true;
 }
 
-static bool containMakeFdsCOENaive(void)
+static bool containPassFd(struct nsjconf_t *nsjconf, int fd)
+{
+       struct fds_t *p;
+       TAILQ_FOREACH(p, &nsjconf->open_fds, pointers) {
+               if (p->fd == fd) {
+                       LOG_D("FD=%d will be passed to the child process", fd);
+                       return true;
+               }
+       }
+       return false;
+}
+
+static bool containMakeFdsCOENaive(struct nsjconf_t *nsjconf)
 {
        // Don't use getrlimit(RLIMIT_NOFILE) here, as it can return an artifically small value
        // (e.g. 32), which could be smaller than a maximum assigned number to file-descriptors
        // in this process. Just use some reasonably sane value (e.g. 1024)
-       for (unsigned fd = (STDERR_FILENO + 1); fd < 1024; fd++) {
+       for (unsigned fd = 0; fd < 1024; fd++) {
                int flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
                if (flags == -1) {
                        continue;
                }
-               TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, flags | FD_CLOEXEC));
-               LOG_D("Set fd '%d' flag to FD_CLOEXEC", fd);
+               if (containPassFd(nsjconf, fd)) {
+                       TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, flags & ~(FD_CLOEXEC)));
+               } else {
+                       TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, flags | FD_CLOEXEC));
+               }
        }
        return true;
 }
 
-static bool containMakeFdsCOEProc(void)
+static bool containMakeFdsCOEProc(struct nsjconf_t *nsjconf)
 {
        /* Make all fds above stderr close-on-exec */
        DIR *dir = opendir("/proc/self/fd");
@@ -234,25 +249,26 @@ static bool containMakeFdsCOEProc(void)
                        LOG_W("Cannot convert /proc/self/fd/%s to a number", entry->d_name);
                        continue;
                }
-               if (fd > STDERR_FILENO) {
-                       int flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
-                       if (flags == -1) {
-                               PLOG_D("fcntl(fd, F_GETFD, 0)");
-                               return false;
-                       }
+               int flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
+               if (flags == -1) {
+                       PLOG_D("fcntl(fd, F_GETFD, 0)");
+                       return false;
+               }
+               if (containPassFd(nsjconf, fd)) {
+                       TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, flags & ~(FD_CLOEXEC)));
+               } else {
                        TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, flags | FD_CLOEXEC));
-                       LOG_D("Set fd '%d' flag to FD_CLOEXEC", fd);
                }
        }
        return true;
 }
 
-static bool containMakeFdsCOE(void)
+static bool containMakeFdsCOE(struct nsjconf_t *nsjconf)
 {
-       if (containMakeFdsCOEProc() == true) {
+       if (containMakeFdsCOEProc(nsjconf) == true) {
                return true;
        }
-       if (containMakeFdsCOENaive() == true) {
+       if (containMakeFdsCOENaive(nsjconf) == true) {
                return true;
        }
        LOG_E("Couldn't mark relevant file-descriptors as close-on-exec with any known method");
@@ -311,7 +327,7 @@ bool containContain(struct nsjconf_t * nsjconf)
        if (containPrepareEnv(nsjconf) == false) {
                return false;
        }
-       if (containMakeFdsCOE() == false) {
+       if (containMakeFdsCOE(nsjconf) == false) {
                return false;
        }
        return true;