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;
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;
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;
}
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;
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;
#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;
#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);
#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) {
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),
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);
}
#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) {
}
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;
+}
#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 */