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;
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;

View File

@ -43,72 +43,55 @@
#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;

View File

@ -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);

View File

@ -46,17 +46,23 @@
#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);
}
char doneChar;
if (utilReadFromFd(pipefd, &doneChar, sizeof(doneChar)) != sizeof(doneChar)) {
exit(1);
}
if (doneChar != subprocDoneChar) {
exit(1);
}
if (containPrepareEnv(nsjconf) == false) {
exit(1);
}
if (containSetupFD(nsjconf, fd_in, fd_out, fd_err, pipefd) == false) {
exit(1);
}
if (containMountFS(nsjconf) == false) {
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)
{
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);
}

64
util.c
View File

@ -21,11 +21,16 @@
#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;
}

6
util.h
View File

@ -21,8 +21,12 @@
#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 */