subproc: move to C++
This commit is contained in:
parent
840b75025c
commit
a2daa94722
8
Makefile
8
Makefile
@ -35,8 +35,8 @@ LDFLAGS += -pie -Wl,-z,noexecstack -lpthread $(shell pkg-config --libs protobuf)
|
||||
|
||||
BIN = nsjail
|
||||
LIBS = kafel/libkafel.a
|
||||
SRCS_C = caps.c contain.c log.c cgroup.c mount.c net.c pid.c sandbox.c subproc.c user.c util.c uts.c cpu.c
|
||||
SRCS_CXX = cmdline.cc config.cc nsjail.cc
|
||||
SRCS_C = caps.c contain.c log.c cgroup.c mount.c net.c pid.c sandbox.c user.c util.c uts.c cpu.c
|
||||
SRCS_CXX = cmdline.cc config.cc nsjail.cc subproc.cc
|
||||
SRCS_PROTO = config.proto
|
||||
SRCS_PB_CXX = $(SRCS_PROTO:.proto=.pb.cc)
|
||||
SRCS_PB_H = $(SRCS_PROTO:.proto=.pb.h)
|
||||
@ -106,8 +106,6 @@ mount.o: mount.h nsjail.h common.h log.h subproc.h util.h
|
||||
net.o: net.h nsjail.h log.h subproc.h
|
||||
pid.o: pid.h nsjail.h log.h subproc.h
|
||||
sandbox.o: sandbox.h nsjail.h kafel/include/kafel.h log.h
|
||||
subproc.o: subproc.h nsjail.h cgroup.h common.h contain.h log.h net.h
|
||||
subproc.o: sandbox.h user.h util.h
|
||||
user.o: user.h nsjail.h common.h log.h subproc.h util.h
|
||||
util.o: util.h nsjail.h common.h log.h
|
||||
uts.o: uts.h nsjail.h log.h
|
||||
@ -117,3 +115,5 @@ cmdline.o: util.h config.h
|
||||
config.o: common.h caps.h nsjail.h config.h log.h mount.h user.h util.h
|
||||
config.o: cmdline.h
|
||||
nsjail.o: nsjail.h cmdline.h common.h log.h net.h subproc.h util.h
|
||||
subproc.o: subproc.h nsjail.h cgroup.h common.h contain.h log.h net.h
|
||||
subproc.o: sandbox.h user.h util.h
|
||||
|
20
nsjail.cc
20
nsjail.cc
@ -111,42 +111,42 @@ static void nsjailListenMode(struct nsjconf_t* nsjconf) {
|
||||
}
|
||||
for (;;) {
|
||||
if (nsjailSigFatal > 0) {
|
||||
subprocKillAll(nsjconf);
|
||||
subproc::killAll(nsjconf);
|
||||
logStop(nsjailSigFatal);
|
||||
close(listenfd);
|
||||
return;
|
||||
}
|
||||
if (nsjailShowProc) {
|
||||
nsjailShowProc = false;
|
||||
subprocDisplay(nsjconf);
|
||||
subproc::displayProc(nsjconf);
|
||||
}
|
||||
int connfd = netAcceptConn(listenfd);
|
||||
if (connfd >= 0) {
|
||||
subprocRunChild(nsjconf, connfd, connfd, connfd);
|
||||
subproc::runChild(nsjconf, connfd, connfd, connfd);
|
||||
close(connfd);
|
||||
}
|
||||
subprocReap(nsjconf);
|
||||
subproc::reapProc(nsjconf);
|
||||
}
|
||||
}
|
||||
|
||||
static int nsjailStandaloneMode(struct nsjconf_t* nsjconf) {
|
||||
subprocRunChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
|
||||
subproc::runChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
|
||||
for (;;) {
|
||||
int child_status = subprocReap(nsjconf);
|
||||
int child_status = subproc::reapProc(nsjconf);
|
||||
|
||||
if (subprocCount(nsjconf) == 0) {
|
||||
if (subproc::countProc(nsjconf) == 0) {
|
||||
if (nsjconf->mode == MODE_STANDALONE_ONCE) {
|
||||
return child_status;
|
||||
}
|
||||
subprocRunChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
|
||||
subproc::runChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
|
||||
continue;
|
||||
}
|
||||
if (nsjailShowProc) {
|
||||
nsjailShowProc = false;
|
||||
subprocDisplay(nsjconf);
|
||||
subproc::displayProc(nsjconf);
|
||||
}
|
||||
if (nsjailSigFatal > 0) {
|
||||
subprocKillAll(nsjconf);
|
||||
subproc::killAll(nsjconf);
|
||||
logStop(nsjailSigFatal);
|
||||
return -1;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" {
|
||||
#include "cgroup.h"
|
||||
#include "common.h"
|
||||
#include "contain.h"
|
||||
@ -51,8 +52,6 @@
|
||||
#include "user.h"
|
||||
#include "util.h"
|
||||
|
||||
static const char kSubprocDoneChar = 'D';
|
||||
|
||||
#if !defined(CLONE_NEWCGROUP)
|
||||
#define CLONE_NEWCGROUP 0x02000000
|
||||
#endif /* !defined(CLONE_NEWCGROUP) */
|
||||
@ -109,8 +108,10 @@ static const char* subprocCloneFlagsToStr(uintptr_t flags) {
|
||||
return cloneFlagName;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
/* Reset the execution environment for the new process */
|
||||
static bool subprocReset(void) {
|
||||
static bool resetEnv(void) {
|
||||
/* Set all previously changed signals to their default behavior */
|
||||
for (size_t i = 0; i < ARRAYSIZE(nssigs); i++) {
|
||||
if (signal(nssigs[i], SIG_DFL) == SIG_ERR) {
|
||||
@ -128,12 +129,16 @@ static bool subprocReset(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace subproc {
|
||||
|
||||
static const char kSubprocDoneChar = 'D';
|
||||
|
||||
static int subprocNewProc(
|
||||
struct nsjconf_t* nsjconf, int fd_in, int fd_out, int fd_err, int pipefd) {
|
||||
if (containSetupFD(nsjconf, fd_in, fd_out, fd_err) == false) {
|
||||
_exit(0xff);
|
||||
}
|
||||
if (!subprocReset()) {
|
||||
if (!resetEnv()) {
|
||||
_exit(0xff);
|
||||
}
|
||||
|
||||
@ -193,8 +198,8 @@ static int subprocNewProc(
|
||||
_exit(0xff);
|
||||
}
|
||||
|
||||
static void subprocAdd(struct nsjconf_t* nsjconf, pid_t pid, int sock) {
|
||||
struct pids_t* p = utilMalloc(sizeof(struct pids_t));
|
||||
static void addProc(struct nsjconf_t* nsjconf, pid_t pid, int sock) {
|
||||
struct pids_t* p = reinterpret_cast<struct pids_t*>(utilMalloc(sizeof(struct pids_t)));
|
||||
p->pid = pid;
|
||||
p->start = time(NULL);
|
||||
netConnToText(
|
||||
@ -210,7 +215,7 @@ static void subprocAdd(struct nsjconf_t* nsjconf, pid_t pid, int sock) {
|
||||
(unsigned int)p->start, p->remote_txt);
|
||||
}
|
||||
|
||||
static void subprocRemove(struct nsjconf_t* nsjconf, pid_t pid) {
|
||||
static void removeProc(struct nsjconf_t* nsjconf, pid_t pid) {
|
||||
struct pids_t* p;
|
||||
TAILQ_FOREACH(p, &nsjconf->pids, pointers) {
|
||||
if (p->pid == pid) {
|
||||
@ -225,15 +230,15 @@ static void subprocRemove(struct nsjconf_t* nsjconf, pid_t pid) {
|
||||
LOG_W("PID: %d not found (?)", pid);
|
||||
}
|
||||
|
||||
int subprocCount(struct nsjconf_t* nsjconf) {
|
||||
int countProc(struct nsjconf_t* nsjconf) {
|
||||
int cnt = 0;
|
||||
struct pids_t* p;
|
||||
TAILQ_FOREACH(p, &nsjconf->pids, pointers) { cnt++; }
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void subprocDisplay(struct nsjconf_t* nsjconf) {
|
||||
LOG_I("Total number of spawned namespaces: %d", subprocCount(nsjconf));
|
||||
void displayProc(struct nsjconf_t* nsjconf) {
|
||||
LOG_I("Total number of spawned namespaces: %d", countProc(nsjconf));
|
||||
time_t now = time(NULL);
|
||||
struct pids_t* p;
|
||||
TAILQ_FOREACH(p, &nsjconf->pids, pointers) {
|
||||
@ -244,7 +249,7 @@ void subprocDisplay(struct nsjconf_t* nsjconf) {
|
||||
}
|
||||
}
|
||||
|
||||
static struct pids_t* subprocGetPidElem(struct nsjconf_t* nsjconf, pid_t pid) {
|
||||
static struct pids_t* getPidElem(struct nsjconf_t* nsjconf, pid_t pid) {
|
||||
struct pids_t* p;
|
||||
TAILQ_FOREACH(p, &nsjconf->pids, pointers) {
|
||||
if (p->pid == pid) {
|
||||
@ -254,10 +259,10 @@ static struct pids_t* subprocGetPidElem(struct nsjconf_t* nsjconf, pid_t pid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void subprocSeccompViolation(struct nsjconf_t* nsjconf, siginfo_t* si) {
|
||||
static void seccompViolation(struct nsjconf_t* nsjconf, siginfo_t* si) {
|
||||
LOG_W("PID: %d commited a syscall/seccomp violation and exited with SIGSYS", si->si_pid);
|
||||
|
||||
struct pids_t* p = subprocGetPidElem(nsjconf, si->si_pid);
|
||||
struct pids_t* p = getPidElem(nsjconf, si->si_pid);
|
||||
if (p == NULL) {
|
||||
LOG_W("PID:%d SiSyscall: %d, SiCode: %d, SiErrno: %d", (int)si->si_pid,
|
||||
si->si_syscall, si->si_code, si->si_errno);
|
||||
@ -293,7 +298,7 @@ static void subprocSeccompViolation(struct nsjconf_t* nsjconf, siginfo_t* si) {
|
||||
}
|
||||
}
|
||||
|
||||
int subprocReap(struct nsjconf_t* nsjconf) {
|
||||
int reapProc(struct nsjconf_t* nsjconf) {
|
||||
int status;
|
||||
int rv = 0;
|
||||
siginfo_t si;
|
||||
@ -307,14 +312,14 @@ int subprocReap(struct nsjconf_t* nsjconf) {
|
||||
break;
|
||||
}
|
||||
if (si.si_code == CLD_KILLED && si.si_status == SIGSYS) {
|
||||
subprocSeccompViolation(nsjconf, &si);
|
||||
seccompViolation(nsjconf, &si);
|
||||
}
|
||||
|
||||
if (wait4(si.si_pid, &status, WNOHANG, NULL) == si.si_pid) {
|
||||
cgroupFinishFromParent(nsjconf, si.si_pid);
|
||||
|
||||
const char* remote_txt = "[UNKNOWN]";
|
||||
struct pids_t* elem = subprocGetPidElem(nsjconf, si.si_pid);
|
||||
struct pids_t* elem = getPidElem(nsjconf, si.si_pid);
|
||||
if (elem) {
|
||||
remote_txt = elem->remote_txt;
|
||||
}
|
||||
@ -322,8 +327,8 @@ int subprocReap(struct nsjconf_t* nsjconf) {
|
||||
if (WIFEXITED(status)) {
|
||||
LOG_I("PID: %d (%s) exited with status: %d, (PIDs left: %d)",
|
||||
si.si_pid, remote_txt, WEXITSTATUS(status),
|
||||
subprocCount(nsjconf) - 1);
|
||||
subprocRemove(nsjconf, si.si_pid);
|
||||
countProc(nsjconf) - 1);
|
||||
removeProc(nsjconf, si.si_pid);
|
||||
rv = WEXITSTATUS(status) % 100;
|
||||
if (rv == 0 && WEXITSTATUS(status) != 0) {
|
||||
rv = 1;
|
||||
@ -333,8 +338,8 @@ int subprocReap(struct nsjconf_t* nsjconf) {
|
||||
LOG_I(
|
||||
"PID: %d (%s) terminated with signal: %s (%d), (PIDs left: %d)",
|
||||
si.si_pid, remote_txt, utilSigName(WTERMSIG(status)),
|
||||
WTERMSIG(status), subprocCount(nsjconf) - 1);
|
||||
subprocRemove(nsjconf, si.si_pid);
|
||||
WTERMSIG(status), countProc(nsjconf) - 1);
|
||||
removeProc(nsjconf, si.si_pid);
|
||||
rv = 100 + WTERMSIG(status);
|
||||
}
|
||||
}
|
||||
@ -364,12 +369,12 @@ int subprocReap(struct nsjconf_t* nsjconf) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
void subprocKillAll(struct nsjconf_t* nsjconf) {
|
||||
void killAll(struct nsjconf_t* nsjconf) {
|
||||
struct pids_t* p;
|
||||
TAILQ_FOREACH(p, &nsjconf->pids, pointers) { kill(p->pid, SIGKILL); }
|
||||
}
|
||||
|
||||
static bool subprocInitParent(struct nsjconf_t* nsjconf, pid_t pid, int pipefd) {
|
||||
static bool initParent(struct nsjconf_t* nsjconf, pid_t pid, int pipefd) {
|
||||
if (netInitNsFromParent(nsjconf, pid) == false) {
|
||||
LOG_E("Couldn't create and put MACVTAP interface into NS of PID '%d'", pid);
|
||||
return false;
|
||||
@ -390,46 +395,7 @@ static bool subprocInitParent(struct nsjconf_t* nsjconf, pid_t pid, int pipefd)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Will be used inside the child process only, so it's safe to have it in BSS.
|
||||
* Some CPU archs (e.g. aarch64) must have it aligned. Size: 128 KiB (/2)
|
||||
*/
|
||||
static uint8_t subprocCloneStack[128 * 1024] __attribute__((aligned(__BIGGEST_ALIGNMENT__)));
|
||||
/* Cannot be on the stack, as the child's stack pointer will change after clone() */
|
||||
static __thread jmp_buf env;
|
||||
|
||||
static int subprocCloneFunc(void* arg __attribute__((unused))) {
|
||||
longjmp(env, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid problems with caching of PID/TID in glibc - when using syscall(__NR_clone) glibc doesn't
|
||||
* update the internal PID/TID caches, what can lead to invalid values being returned by getpid()
|
||||
* or incorrect PID/TIDs used in raise()/abort() functions
|
||||
*/
|
||||
pid_t subprocClone(uintptr_t flags) {
|
||||
if (flags & CLONE_VM) {
|
||||
LOG_E("Cannot use clone(flags & CLONE_VM)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setjmp(env) == 0) {
|
||||
LOG_D("Cloning process with flags:%s", subprocCloneFlagsToStr(flags));
|
||||
/*
|
||||
* Avoid the problem of the stack growing up/down under different CPU architectures,
|
||||
* by using middle of the static stack buffer (which is temporary, and used only
|
||||
* inside of the subprocCloneFunc()
|
||||
*/
|
||||
void* stack = &subprocCloneStack[sizeof(subprocCloneStack) / 2];
|
||||
/* Parent */
|
||||
return clone(subprocCloneFunc, stack, flags, NULL, NULL, NULL);
|
||||
}
|
||||
/* Child */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void subprocRunChild(struct nsjconf_t* nsjconf, int fd_in, int fd_out, int fd_err) {
|
||||
void runChild(struct nsjconf_t* nsjconf, int fd_in, int fd_out, int fd_err) {
|
||||
if (netLimitConns(nsjconf, fd_in) == false) {
|
||||
return;
|
||||
}
|
||||
@ -483,9 +449,9 @@ void subprocRunChild(struct nsjconf_t* nsjconf, int fd_in, int fd_out, int fd_er
|
||||
close(parent_fd);
|
||||
return;
|
||||
}
|
||||
subprocAdd(nsjconf, pid, fd_in);
|
||||
addProc(nsjconf, pid, fd_in);
|
||||
|
||||
if (subprocInitParent(nsjconf, pid, parent_fd) == false) {
|
||||
if (initParent(nsjconf, pid, parent_fd) == false) {
|
||||
close(parent_fd);
|
||||
return;
|
||||
}
|
||||
@ -495,6 +461,47 @@ void subprocRunChild(struct nsjconf_t* nsjconf, int fd_in, int fd_out, int fd_er
|
||||
netConnToText(fd_in, true /* remote */, cs_addr, sizeof(cs_addr), NULL);
|
||||
}
|
||||
|
||||
} // namespace subproc
|
||||
|
||||
/*
|
||||
* Will be used inside the child process only, so it's safe to have it in BSS.
|
||||
* Some CPU archs (e.g. aarch64) must have it aligned. Size: 128 KiB (/2)
|
||||
*/
|
||||
static uint8_t subprocCloneStack[128 * 1024] __attribute__((aligned(__BIGGEST_ALIGNMENT__)));
|
||||
/* Cannot be on the stack, as the child's stack pointer will change after clone() */
|
||||
static __thread jmp_buf env;
|
||||
|
||||
static int subprocCloneFunc(void* arg __attribute__((unused))) {
|
||||
longjmp(env, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid problems with caching of PID/TID in glibc - when using syscall(__NR_clone) glibc doesn't
|
||||
* update the internal PID/TID caches, what can lead to invalid values being returned by getpid()
|
||||
* or incorrect PID/TIDs used in raise()/abort() functions
|
||||
*/
|
||||
pid_t subprocClone(uintptr_t flags) {
|
||||
if (flags & CLONE_VM) {
|
||||
LOG_E("Cannot use clone(flags & CLONE_VM)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setjmp(env) == 0) {
|
||||
LOG_D("Cloning process with flags:%s", subprocCloneFlagsToStr(flags));
|
||||
/*
|
||||
* Avoid the problem of the stack growing up/down under different CPU architectures,
|
||||
* by using middle of the static stack buffer (which is temporary, and used only
|
||||
* inside of the subprocCloneFunc()
|
||||
*/
|
||||
void* stack = &subprocCloneStack[sizeof(subprocCloneStack) / 2];
|
||||
/* Parent */
|
||||
return clone(subprocCloneFunc, stack, flags, NULL, NULL, NULL);
|
||||
}
|
||||
/* Child */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int subprocSystem(const char** argv, char** env) {
|
||||
bool exec_failed = false;
|
||||
|
20
subproc.h
20
subproc.h
@ -29,22 +29,26 @@
|
||||
#include "nsjail.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace subproc {
|
||||
|
||||
void runChild(struct nsjconf_t* nsjconf, int fd_in, int fd_out, int fd_err);
|
||||
int countProc(struct nsjconf_t* nsjconf);
|
||||
void displayProc(struct nsjconf_t* nsjconf);
|
||||
void killAll(struct nsjconf_t* nsjconf);
|
||||
/* Returns the exit code of the first failing subprocess, or 0 if none fail */
|
||||
int reapProc(struct nsjconf_t* nsjconf);
|
||||
|
||||
} // namespace subproc
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void subprocRunChild(struct nsjconf_t* nsjconf, int fd_in, int fd_out, int fd_err);
|
||||
int subprocCount(struct nsjconf_t* nsjconf);
|
||||
void subprocDisplay(struct nsjconf_t* nsjconf);
|
||||
void subprocKillAll(struct nsjconf_t* nsjconf);
|
||||
int subprocSystem(const char** argv, char** env);
|
||||
pid_t subprocClone(uintptr_t flags);
|
||||
void subprocCloneFlags(struct nsjconf_t* nsjconf);
|
||||
|
||||
/* Returns the exit code of the first failing subprocess, or 0 if none fail */
|
||||
int subprocReap(struct nsjconf_t* nsjconf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* NS_PROC_H */
|
||||
|
Loading…
Reference in New Issue
Block a user