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
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.."},
{{"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)"},
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;
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,
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 */
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");
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");
if (containPrepareEnv(nsjconf) == false) {
return false;
}
- if (containMakeFdsCOE() == false) {
+ if (containMakeFdsCOE(nsjconf) == false) {
return false;
}
return true;