Initialize user/group maps from the parent process
This commit is contained in:
parent
ad4b0105a7
commit
8d641169e3
12
cmdline.c
12
cmdline.c
@ -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;
|
||||||
|
57
contain.c
57
contain.c
@ -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;
|
||||||
|
@ -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);
|
||||||
|
38
subproc.c
38
subproc.c
@ -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
64
util.c
@ -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
6
util.h
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user