Implementation of MODE_STANDALONE_EXECVE

This commit is contained in:
Jagger 2015-08-15 16:02:38 +02:00
parent 5dc0fe193a
commit 701825970a
6 changed files with 79 additions and 24 deletions

View File

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

View File

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

View File

@ -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
View File

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

View File

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

View File

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