Initialize user/group maps from the parent process

This commit is contained in:
Jagger 2016-02-28 02:34:43 +01:00
parent ad4b0105a7
commit 8d641169e3
6 changed files with 121 additions and 58 deletions

View File

@ -486,14 +486,14 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
break; break;
case 'E': case 'E':
{ {
struct charptr_t *p = util_malloc(sizeof(struct charptr_t)); struct charptr_t *p = utilMalloc(sizeof(struct charptr_t));
p->val = optarg; p->val = optarg;
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers); TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
} }
break; break;
case 'R': 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->src = optarg;
p->dst = cmdlineSplitStrByColon(optarg); p->dst = cmdlineSplitStrByColon(optarg);
p->flags = MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY; 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; break;
case 'B': 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->src = optarg;
p->dst = cmdlineSplitStrByColon(optarg); p->dst = cmdlineSplitStrByColon(optarg);
p->flags = MS_BIND | MS_REC | MS_PRIVATE; p->flags = MS_BIND | MS_REC | MS_PRIVATE;
@ -515,7 +515,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
break; break;
case 'T': case 'T':
{ {
struct mounts_t *p = util_malloc(sizeof(struct mounts_t)); struct mounts_t *p = utilMalloc(sizeof(struct mounts_t));
p->src = "/"; p->src = "/";
p->dst = optarg; p->dst = optarg;
p->flags = 0; p->flags = 0;
@ -559,7 +559,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
} }
if (nsjconf->mount_proc == true) { 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->src = "/proc";
p->dst = "/proc"; p->dst = "/proc";
p->flags = 0; p->flags = 0;
@ -568,7 +568,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
TAILQ_INSERT_HEAD(&nsjconf->mountpts, p, pointers); 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->src = nsjconf->chroot;
p->dst = "/"; p->dst = "/";
p->flags = MS_BIND | MS_REC | MS_PRIVATE; p->flags = MS_BIND | MS_REC | MS_PRIVATE;

View File

@ -43,72 +43,55 @@
#include <unistd.h> #include <unistd.h>
#include "log.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); char fname[PATH_MAX];
if (fd == -1) { snprintf(fname, sizeof(fname), "/proc/%d/setgroups", pid);
/* Not present in all kernels */
PLOG_D("'/proc/self/setgroups' not present in this kernel?");
return true;
}
const char *denystr = "deny"; const char *denystr = "deny";
if (write(fd, denystr, strlen(denystr)) == -1) { if (utilWriteBufToFile(fname, denystr, strlen(denystr), O_WRONLY) == false) {
PLOG_E("write('/proc/self/setgroups', '%s') failed", denystr); LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, denystr);
close(fd);
return false; return false;
} }
close(fd);
return true; return true;
} }
static bool containUidGidMap(struct nsjconf_t *nsjconf) static bool containUidGidMap(struct nsjconf_t *nsjconf, pid_t pid)
{ {
if (nsjconf->clone_newuser == false) { if (nsjconf->clone_newuser == false) {
return true; return true;
} }
sleep(10); char fname[PATH_MAX];
return true; char map[128];
int fd; snprintf(fname, sizeof(fname), "/proc/%d/uid_map", pid);
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(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_uid, snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_uid,
(unsigned long)nsjconf->outside_uid); (unsigned long)nsjconf->outside_uid);
LOG_D("Writing '%s' to /proc/self/uid_map", map); LOG_D("Writing '%s' to '%s'", map, fname);
if (write(fd, map, strlen(map)) == -1) { if (utilWriteBufToFile(fname, map, strlen(map), O_WRONLY) == false) {
PLOG_E("write('/proc/self/uid_map', %d, '%s')", fd, map); LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, map);
close(fd);
return false; return false;
} }
close(fd);
if ((fd = open("/proc/self/gid_map", O_WRONLY | O_CLOEXEC)) == -1) { snprintf(fname, sizeof(fname), "/proc/%d/gid_map", pid);
PLOG_E("open('/proc/self/gid_map', O_WRONLY | O_CLOEXEC)");
return false;
}
snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_gid, snprintf(map, sizeof(map), "%lu %lu 1", (unsigned long)nsjconf->inside_gid,
(unsigned long)nsjconf->outside_gid); (unsigned long)nsjconf->outside_gid);
LOG_D("Writing '%s' to /proc/self/gid_map", map); LOG_D("Writing '%s' to '%s'", map, fname);
if (write(fd, map, strlen(map)) == -1) { if (utilWriteBufToFile(fname, map, strlen(map), O_WRONLY) == false) {
PLOG_E("write('/proc/self/gid_map', %d, '%s')", fd, map); LOG_E("utilWriteBufToFile('%s', '%s') failed", fname, map);
close(fd);
return false; return false;
} }
close(fd);
return true; 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; return false;
} }
if (containUidGidMap(nsjconf) == false) { if (containUidGidMap(nsjconf, pid) == false) {
return false; return false;
} }
return true; return true;

View File

@ -26,7 +26,7 @@
#include "common.h" #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 containDropPrivs(struct nsjconf_t *nsjconf);
bool containPrepareEnv(struct nsjconf_t *nsjconf); bool containPrepareEnv(struct nsjconf_t *nsjconf);
bool containMountFS(struct nsjconf_t *nsjconf); bool containMountFS(struct nsjconf_t *nsjconf);

View File

@ -46,17 +46,23 @@
#include "sandbox.h" #include "sandbox.h"
#include "util.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) 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);
}
char doneChar;
if (utilReadFromFd(pipefd, &doneChar, sizeof(doneChar)) != sizeof(doneChar)) {
exit(1);
}
if (doneChar != subprocDoneChar) {
exit(1); exit(1);
} }
if (containPrepareEnv(nsjconf) == false) { if (containPrepareEnv(nsjconf) == false) {
exit(1); exit(1);
} }
if (containSetupFD(nsjconf, fd_in, fd_out, fd_err, pipefd) == false) {
exit(1);
}
if (containMountFS(nsjconf) == false) { if (containMountFS(nsjconf) == false) {
exit(1); exit(1);
} }
@ -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) 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->pid = pid;
p->start = time(NULL); p->start = time(NULL);
netConnToText(sock, true /* remote */ , p->remote_txt, sizeof(p->remote_txt), 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; flags |= SIGCHLD;
LOG_D("Creating new process with clone flags: %#x", flags); LOG_D("Creating new process with clone flags: %#x", flags);
int pipefd[2]; int sv[2];
if (pipe2(pipefd, O_CLOEXEC) == -1) { if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) == -1) {
PLOG_E("pipe2(pipefd, O_CLOEXEC) failed"); PLOG_E("socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC) failed");
return; return;
} }
pid_t pid = syscall(__NR_clone, (uintptr_t) flags, NULL, NULL, NULL, (uintptr_t) 0); pid_t pid = syscall(__NR_clone, (uintptr_t) flags, NULL, NULL, NULL, (uintptr_t) 0);
if (pid == 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) { if (pid == -1) {
PLOG_E("clone(flags=%#x) failed. You probably need root privileges if your system " 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 " "doesn't support CLONE_NEWUSER. Alternatively, you might want to recompile your "
"kernel with support for namespaces or check the setting of the " "kernel with support for namespaces or check the setting of the "
"kernel.unprivileged_userns_clone sysctl", flags); "kernel.unprivileged_userns_clone sysctl", flags);
close(sv[1]);
return; return;
} }
if (netCloneMacVtapAndNS(nsjconf, pid) == false) { if (netCloneMacVtapAndNS(nsjconf, pid) == false) {
LOG_E("Couldn't create and put MACVTAP interface into NS of PID '%d'", pid); 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]; char cs_addr[64];
netConnToText(fd_in, true /* remote */ , cs_addr, sizeof(cs_addr), NULL); 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); LOG_I("PID: %d about to execute '%s' for %s", pid, nsjconf->argv[0], cs_addr);
char log_buf[4096]; char log_buf[4096];
close(pipefd[1]);
ssize_t sz; 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'; log_buf[sz] = '\0';
logDirectlyToFD(log_buf); logDirectlyToFD(log_buf);
} }
close(pipefd[0]); close(sv[1]);
subprocAdd(nsjconf, pid, fd_in); subprocAdd(nsjconf, pid, fd_in);
} }

64
util.c
View File

@ -21,11 +21,16 @@
#include "util.h" #include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "log.h" #include "log.h"
void *util_malloc(size_t sz) void *utilMalloc(size_t sz)
{ {
void *ret = malloc(sz); void *ret = malloc(sz);
if (ret == NULL) { if (ret == NULL) {
@ -33,3 +38,60 @@ void *util_malloc(size_t sz)
} }
return ret; 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;
}

6
util.h
View File

@ -21,8 +21,12 @@
#ifndef _UTIL_H #ifndef _UTIL_H
#define _UTIL_H #define _UTIL_H
#include <stdbool.h>
#include <stdlib.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 */ #endif /* _UTIL_H */