Implementation of MODE_STANDALONE_EXECVE
This commit is contained in:
parent
5dc0fe193a
commit
701825970a
40
cmdline.c
40
cmdline.c
@ -74,6 +74,9 @@ void cmdlineLogParams(struct nsjconf_t *nsjconf)
|
||||
case MODE_STANDALONE_ONCE:
|
||||
LOG_I("Mode: STANDALONE_ONCE");
|
||||
break;
|
||||
case MODE_STANDALONE_EXECVE:
|
||||
LOG_I("Mode: STANDALONE_EXECVE");
|
||||
break;
|
||||
case MODE_STANDALONE_RERUN:
|
||||
LOG_I("Mode: STANDALONE_RERUN");
|
||||
break;
|
||||
@ -183,6 +186,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
.initial_gid = getgid(),
|
||||
.max_conns_per_ip = 0,
|
||||
.tmpfs_size = 4 * (1024 * 1024),
|
||||
.mount_proc = true,
|
||||
};
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
@ -200,7 +204,8 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
{{"help", no_argument, NULL, 'h'}, "Help plz.."},
|
||||
{{"mode", required_argument, NULL, 'M'}, "Execution mode (default: l [MODE_LISTEN_TCP]):\n"
|
||||
"\tl: Listen to connections on a TCP port (specified with --port) [MODE_LISTEN_TCP]\n"
|
||||
"\to: Immediately launch a single process on a console [MODE_STANDALONE_ONCE]\n"
|
||||
"\to: Immediately launch a single process on a console using clone/execve [MODE_STANDALONE_ONCE]\n"
|
||||
"\te: Immediately launch a single process on a console using execve [MODE_STANDALONE_EXECVE]\n"
|
||||
"\tr: Immediately launch a single process on a console, keep doing it forever [MODE_STANDALONE_RERUN]"},
|
||||
{{"chroot", required_argument, NULL, 'c'}, "Directory containing / of the jail (default: '/chroot')"},
|
||||
{{"user", required_argument, NULL, 'u'}, "Username/uid of processess inside the jail (default: 'nobody')"},
|
||||
@ -213,7 +218,9 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
{{"daemon", no_argument, NULL, 'd'}, "Daemonize after start? (default: false)"},
|
||||
{{"verbose", no_argument, NULL, 'v'}, "Verbose output (default: false)"},
|
||||
{{"keep_env", no_argument, NULL, 'e'}, "Should all environment variables be passed to the child? (default: false)"},
|
||||
{{"keep_caps", no_argument, NULL, 0x0502}, "Don't drop capabilities (DANGEROUS) (default: false)"},
|
||||
{{"keep_caps", no_argument, NULL, 0x0501}, "Don't drop capabilities (DANGEROUS) (default: false)"},
|
||||
{{"silent", no_argument, NULL, 0x0502}, "Redirect child's fd:0/1/2 to /dev/null (default: false)"},
|
||||
{{"disable_sandbox", no_argument, NULL, 0x0503}, "Don't enable the seccomp-bpf sandboxing (default: false)"},
|
||||
{{"rlimit_as", required_argument, NULL, 0x0201}, "RLIMIT_AS in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 512)"},
|
||||
{{"rlimit_core", required_argument, NULL, 0x0202}, "RLIMIT_CORE in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 0)"},
|
||||
{{"rlimit_cpu", required_argument, NULL, 0x0203}, "RLIMIT_CPU, 'max' for RLIM_INFINITY, 'def' for the current value (default: 600)"},
|
||||
@ -232,14 +239,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
{{"disable_clone_newpid", no_argument, NULL, 0x0404}, "Don't use CLONE_NEWPID (default: false)"},
|
||||
{{"disable_clone_newipc", no_argument, NULL, 0x0405}, "Don't use CLONE_NEWIPC (default: false)"},
|
||||
{{"disable_clone_newuts", no_argument, NULL, 0x0406}, "Don't use CLONE_NEWUTS (default: false)"},
|
||||
{{"disable_sandbox", no_argument, NULL, 0x0501}, "Don't enable the seccomp-bpf sandboxing (default: false)"},
|
||||
{{"rw", no_argument, NULL, 0x0503}, "Mount / as RW (default: RO)"},
|
||||
{{"silent", no_argument, NULL, 0x0504}, "Redirect child's fd:0/1/2 to /dev/null (default: false)"},
|
||||
{{"rw", no_argument, NULL, 0x0601}, "Mount / as RW (default: RO)"},
|
||||
{{"bindmount_ro", required_argument, NULL, 'R'}, "List of mountpoints to be mounted --bind (ro) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'. (default: none)"},
|
||||
{{"bindmount", required_argument, NULL, 'B'}, "List of mountpoints to be mounted --bind (rw) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'. (default: none)"},
|
||||
{{"tmpfsmount", required_argument, NULL, 'T'}, "List of mountpoints to be mounted as RW/tmpfs inside the container. Can be specified multiple times. Supports 'dest' syntax. (default: none)"},
|
||||
{{"iface", required_argument, NULL, 'I'}, "Interface which will be cloned (MACVTAP) and put inside the subprocess' namespace"},
|
||||
{{"tmpfs_size", required_argument, NULL, 0x0506}, "Number of bytes to allocate for tmpfsmounts in bytes (default: 4194304)"},
|
||||
{{"tmpfs_size", required_argument, NULL, 0x0602}, "Number of bytes to allocate for tmpfsmounts (default: 4194304)"},
|
||||
{{"disable_proc", no_argument, NULL, 0x0603}, "Disable mounting /proc (default: false)"},
|
||||
{{0, 0, 0, 0}, NULL},
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
@ -268,9 +274,6 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
case 'i':
|
||||
nsjconf->max_conns_per_ip = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 0x0506:
|
||||
nsjconf->tmpfs_size = strtoull(optarg, NULL, 0);
|
||||
break;
|
||||
case 'u':
|
||||
user = optarg;
|
||||
break;
|
||||
@ -351,16 +354,22 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
nsjconf->clone_newuts = false;
|
||||
break;
|
||||
case 0x0501:
|
||||
nsjconf->apply_sandbox = false;
|
||||
break;
|
||||
case 0x0502:
|
||||
nsjconf->keep_caps = true;
|
||||
break;
|
||||
case 0x0502:
|
||||
nsjconf->is_silent = true;
|
||||
break;
|
||||
case 0x0503:
|
||||
nsjconf->apply_sandbox = false;
|
||||
break;
|
||||
case 0x0601:
|
||||
nsjconf->is_root_rw = true;
|
||||
break;
|
||||
case 0x0504:
|
||||
nsjconf->is_silent = true;
|
||||
case 0x0602:
|
||||
nsjconf->tmpfs_size = strtoull(optarg, NULL, 0);
|
||||
break;
|
||||
case 0x0603:
|
||||
nsjconf->mount_proc = false;
|
||||
break;
|
||||
case 'R':
|
||||
{
|
||||
@ -400,6 +409,9 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
|
||||
case 'o':
|
||||
nsjconf->mode = MODE_STANDALONE_ONCE;
|
||||
break;
|
||||
case 'e':
|
||||
nsjconf->mode = MODE_STANDALONE_EXECVE;
|
||||
break;
|
||||
case 'r':
|
||||
nsjconf->mode = MODE_STANDALONE_RERUN;
|
||||
break;
|
||||
|
2
common.h
2
common.h
@ -46,6 +46,7 @@ struct constchar_t {
|
||||
enum mode_t {
|
||||
MODE_LISTEN_TCP = 0,
|
||||
MODE_STANDALONE_ONCE,
|
||||
MODE_STANDALONE_EXECVE,
|
||||
MODE_STANDALONE_RERUN
|
||||
};
|
||||
|
||||
@ -84,6 +85,7 @@ struct nsjconf_t {
|
||||
gid_t initial_gid;
|
||||
unsigned int max_conns_per_ip;
|
||||
size_t tmpfs_size;
|
||||
bool mount_proc;
|
||||
LIST_HEAD(pidslist, pids_t) pids;
|
||||
LIST_HEAD(rwbindmountptslist, constchar_t) rwbindmountpts;
|
||||
LIST_HEAD(robindmountptslist, constchar_t) robindmountpts;
|
||||
|
34
contain.c
34
contain.c
@ -270,6 +270,30 @@ static bool remountBindMount(const char *spec, unsigned long flags)
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool containMountProc(struct nsjconf_t *nsjconf, const char *newrootdir)
|
||||
{
|
||||
char procrootdir[PATH_MAX];
|
||||
snprintf(procrootdir, sizeof(procrootdir), "%s/proc", newrootdir);
|
||||
|
||||
if (nsjconf->mount_proc == false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
|
||||
if (mount("/proc", procrootdir, NULL, MS_REC | MS_BIND, NULL) == -1) {
|
||||
PLOG_E("mount('/proc', '%s', MS_REC|MS_BIND)", procrootdir);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (mount(NULL, procrootdir, "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL) == -1) {
|
||||
PLOG_E("mount('%s', 'proc')", procrootdir);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool containMountFS(struct nsjconf_t * nsjconf)
|
||||
{
|
||||
const char *destdir = "/tmp";
|
||||
@ -287,11 +311,7 @@ bool containMountFS(struct nsjconf_t * nsjconf)
|
||||
PLOG_E("mount('%s', '%s', MS_BIND | MS_REC)", nsjconf->chroot, newrootdir);
|
||||
return false;
|
||||
}
|
||||
|
||||
char procrootdir[PATH_MAX];
|
||||
snprintf(procrootdir, sizeof(procrootdir), "%s/proc", newrootdir);
|
||||
if (mount(NULL, procrootdir, "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL) == -1) {
|
||||
PLOG_E("mount('%s', 'proc')", procrootdir);
|
||||
if (containMountProc(nsjconf, newrootdir) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -455,7 +475,9 @@ bool containMakeFdsCOE(void)
|
||||
bool containSetupFD(struct nsjconf_t * nsjconf, int fd_in, int fd_out, int fd_err, int fd_log)
|
||||
{
|
||||
/* Make sure all logs go to the parent process from now on */
|
||||
logRedirectLogFD(fd_log);
|
||||
if (fd_log != -1) {
|
||||
logRedirectLogFD(fd_log);
|
||||
}
|
||||
|
||||
if (nsjconf->mode != MODE_LISTEN_TCP) {
|
||||
if (nsjconf->is_silent == false) {
|
||||
|
2
log.c
2
log.c
@ -52,7 +52,7 @@ bool logInitLogFile(struct nsjconf_t *nsjconf, const char *logfile, bool is_verb
|
||||
logfile = _LOG_DEFAULT_FILE;
|
||||
}
|
||||
if (logfile == NULL) {
|
||||
logfile = "/dev/tty";
|
||||
logfile = "/proc/self/fd/2";
|
||||
}
|
||||
log_fd = open(logfile, O_CREAT | O_RDWR | O_APPEND, 0640);
|
||||
if (log_fd == -1) {
|
||||
|
8
nsjail.c
8
nsjail.c
@ -92,8 +92,12 @@ static bool nsjailSetSigHandlers(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nsjailSetTimer(void)
|
||||
static bool nsjailSetTimer(struct nsjconf_t *nsjconf)
|
||||
{
|
||||
if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct itimerval it = {
|
||||
.it_value = {.tv_sec = 1,.tv_usec = 0},
|
||||
.it_interval = {.tv_sec = 1,.tv_usec = 0},
|
||||
@ -173,7 +177,7 @@ int main(int argc, char *argv[])
|
||||
if (nsjailSetSigHandlers() == false) {
|
||||
exit(1);
|
||||
}
|
||||
if (nsjailSetTimer() == false) {
|
||||
if (nsjailSetTimer(&nsjconf) == false) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
17
subproc.c
17
subproc.c
@ -204,7 +204,7 @@ void subprocRunChild(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int fd_er
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int flags = SIGCHLD;
|
||||
unsigned int flags = 0UL;
|
||||
flags |= (nsjconf->clone_newnet ? CLONE_NEWNET : 0);
|
||||
flags |= (nsjconf->clone_newuser ? CLONE_NEWUSER : 0);
|
||||
flags |= (nsjconf->clone_newns ? CLONE_NEWNS : 0);
|
||||
@ -212,6 +212,21 @@ void subprocRunChild(struct nsjconf_t *nsjconf, int fd_in, int fd_out, int fd_er
|
||||
flags |= (nsjconf->clone_newipc ? CLONE_NEWIPC : 0);
|
||||
flags |= (nsjconf->clone_newuts ? CLONE_NEWUTS : 0);
|
||||
|
||||
if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
|
||||
if (nsjconf->clone_newpid) {
|
||||
LOG_W("CLONE_NEWPID requested. It causes troubles with unshare() "
|
||||
"[ENOMEM with clone/fork/vfork]. Disabling it");
|
||||
flags &= ~(CLONE_NEWPID);
|
||||
}
|
||||
LOG_D("Entering namespace with flags: %#x", flags);
|
||||
if (unshare(flags) == -1) {
|
||||
PLOG_E("unshare(%u)", flags);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
subprocNewProc(nsjconf, fd_in, fd_out, fd_err, -1);
|
||||
}
|
||||
|
||||
flags |= SIGCHLD;
|
||||
LOG_D("Creating new process with clone flags: %#x", flags);
|
||||
|
||||
int pipefd[2];
|
||||
|
Loading…
Reference in New Issue
Block a user