219 lines
4.6 KiB
C
219 lines
4.6 KiB
C
|
/*
|
||
|
|
||
|
nsjail
|
||
|
-----------------------------------------
|
||
|
|
||
|
Copyright 2014 Google Inc. All Rights Reserved.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
|
||
|
*/
|
||
|
#include "nsjail.h"
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <signal.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include "cmdline.h"
|
||
|
#include "common.h"
|
||
|
#include "log.h"
|
||
|
#include "net.h"
|
||
|
#include "subproc.h"
|
||
|
|
||
|
static __thread int nsjailSigFatal = 0;
|
||
|
static __thread bool nsjailShowProc = false;
|
||
|
|
||
|
static void nsjailSig(int sig)
|
||
|
{
|
||
|
if (sig == SIGALRM) {
|
||
|
return;
|
||
|
}
|
||
|
if (sig == SIGCHLD) {
|
||
|
return;
|
||
|
}
|
||
|
if (sig == SIGUSR1) {
|
||
|
nsjailShowProc = true;
|
||
|
return;
|
||
|
}
|
||
|
nsjailSigFatal = sig;
|
||
|
}
|
||
|
|
||
|
static bool nsjailSetSigHandler(int sig)
|
||
|
{
|
||
|
LOG_D("Setting sighandler for signal '%d' (%s)", sig, strsignal(sig));
|
||
|
|
||
|
sigset_t smask;
|
||
|
sigemptyset(&smask);
|
||
|
struct sigaction sa = {
|
||
|
.sa_handler = nsjailSig,
|
||
|
.sa_mask = smask,
|
||
|
.sa_flags = 0,
|
||
|
.sa_restorer = NULL,
|
||
|
};
|
||
|
if (sigaction(sig, &sa, NULL) == -1) {
|
||
|
PLOG_E("sigaction(%d)", sig);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool nsjailSetSigHandlers(void)
|
||
|
{
|
||
|
if (nsjailSetSigHandler(SIGINT) == false) {
|
||
|
return false;
|
||
|
}
|
||
|
if (nsjailSetSigHandler(SIGUSR1) == false) {
|
||
|
return false;
|
||
|
}
|
||
|
if (nsjailSetSigHandler(SIGALRM) == false) {
|
||
|
return false;
|
||
|
}
|
||
|
if (nsjailSetSigHandler(SIGCHLD) == false) {
|
||
|
return false;
|
||
|
}
|
||
|
if (nsjailSetSigHandler(SIGTERM) == false) {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool nsjailSetTimer(void)
|
||
|
{
|
||
|
struct itimerval it = {
|
||
|
.it_value = {.tv_sec = 1,.tv_usec = 0},
|
||
|
.it_interval = {.tv_sec = 1,.tv_usec = 0},
|
||
|
};
|
||
|
if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
|
||
|
PLOG_E("setitimer(ITIMER_REAL)");
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static void nsjailListenMode(struct nsjconf_t *nsjconf)
|
||
|
{
|
||
|
int listenfd = netGetRecvSocket(nsjconf->port);
|
||
|
if (listenfd == -1) {
|
||
|
return;
|
||
|
}
|
||
|
for (;;) {
|
||
|
if (nsjailSigFatal > 0) {
|
||
|
subprocKillAll(nsjconf);
|
||
|
logStop(nsjailSigFatal);
|
||
|
return;
|
||
|
}
|
||
|
if (nsjailShowProc == true) {
|
||
|
nsjailShowProc = false;
|
||
|
subprocDisplay(nsjconf);
|
||
|
}
|
||
|
int connfd = netAcceptConn(listenfd);
|
||
|
if (connfd >= 0) {
|
||
|
subprocRunChild(nsjconf, connfd, connfd, connfd);
|
||
|
close(connfd);
|
||
|
}
|
||
|
subprocReap(nsjconf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void nsjailStandaloneMode(struct nsjconf_t *nsjconf)
|
||
|
{
|
||
|
subprocRunChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
|
||
|
for (;;) {
|
||
|
if (subprocCount(nsjconf) == 0) {
|
||
|
if (nsjconf->mode == MODE_STANDALONE_ONCE) {
|
||
|
return;
|
||
|
}
|
||
|
subprocRunChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
|
||
|
}
|
||
|
if (nsjailShowProc == true) {
|
||
|
nsjailShowProc = false;
|
||
|
subprocDisplay(nsjconf);
|
||
|
}
|
||
|
if (nsjailSigFatal > 0) {
|
||
|
subprocKillAll(nsjconf);
|
||
|
logStop(nsjailSigFatal);
|
||
|
return;
|
||
|
}
|
||
|
pause();
|
||
|
subprocReap(nsjconf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
struct nsjconf_t nsjconf = {
|
||
|
.hostname = "NSJAIL",
|
||
|
.chroot = "/chroot",
|
||
|
.argv = NULL,
|
||
|
.port = 31337,
|
||
|
.uid = -1,
|
||
|
.gid = -1,
|
||
|
.daemonize = false,
|
||
|
.tlimit = 0,
|
||
|
.apply_sandbox = true,
|
||
|
.verbose = false,
|
||
|
.keep_caps = false,
|
||
|
.rl_as = 512 * (1024 * 1024),
|
||
|
.rl_core = 0,
|
||
|
.rl_cpu = 600,
|
||
|
.rl_fsize = 1 * (1024 * 1024),
|
||
|
.rl_nofile = 32,
|
||
|
.rl_nproc = cmdlineParseRLimit(RLIMIT_NPROC, "def", 1),
|
||
|
.rl_stack = cmdlineParseRLimit(RLIMIT_STACK, "def", 1),
|
||
|
.personality = 0,
|
||
|
.clone_newnet = true,
|
||
|
.clone_newuser = true,
|
||
|
.clone_newns = true,
|
||
|
.clone_newpid = true,
|
||
|
.clone_newipc = true,
|
||
|
.clone_newuts = true,
|
||
|
.mode = MODE_LISTEN_TCP,
|
||
|
.is_root_rw = false,
|
||
|
.is_silent = false,
|
||
|
.bindmountpts = NULL,
|
||
|
.tmpfsmountpts = NULL,
|
||
|
.initial_uid = getuid(),
|
||
|
.initial_gid = getgid(),
|
||
|
.max_conns_per_ip = 0,
|
||
|
};
|
||
|
|
||
|
if (!cmdlineParse(argc, argv, &nsjconf)) {
|
||
|
exit(1);
|
||
|
}
|
||
|
if (nsjconf.clone_newuser == false && geteuid() != 0) {
|
||
|
LOG_E("--disable_clone_newuser requires root() privs");
|
||
|
}
|
||
|
if (nsjconf.daemonize && (daemon(0, 0) == -1)) {
|
||
|
PLOG_F("daemon");
|
||
|
}
|
||
|
cmdlineLogParams(&nsjconf);
|
||
|
if (nsjailSetSigHandlers() == false) {
|
||
|
exit(1);
|
||
|
}
|
||
|
if (nsjailSetTimer() == false) {
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
if (nsjconf.mode == MODE_LISTEN_TCP) {
|
||
|
nsjailListenMode(&nsjconf);
|
||
|
} else {
|
||
|
nsjailStandaloneMode(&nsjconf);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|