2015-05-15 05:44:48 +08:00
/*
nsjail - cmdline parsing
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 "cmdline.h"
# include <ctype.h>
# include <errno.h>
2016-02-29 06:40:34 +08:00
# include <fcntl.h>
2015-05-15 05:44:48 +08:00
# include <getopt.h>
# include <grp.h>
# include <limits.h>
# include <pwd.h>
# include <stdbool.h>
# include <stdio.h>
2017-05-11 22:17:54 +08:00
# include <stdlib.h>
2015-10-17 22:48:30 +08:00
# include <string.h>
2015-05-15 05:44:48 +08:00
# include <strings.h>
2015-10-17 22:48:30 +08:00
# include <sys/mount.h>
2017-05-11 22:17:54 +08:00
# include <sys/personality.h>
2018-02-09 22:44:29 +08:00
# include <sys/resource.h>
2017-10-18 23:57:52 +08:00
# include <sys/stat.h>
# include <sys/syscall.h>
2016-02-29 06:40:34 +08:00
# include <sys/types.h>
2015-05-15 05:44:48 +08:00
# include <unistd.h>
2018-02-09 22:44:29 +08:00
# include <memory>
2018-02-11 21:56:30 +08:00
# include <string>
# include <vector>
2018-02-09 22:44:29 +08:00
2018-02-10 00:49:13 +08:00
# include "caps.h"
2018-02-09 22:44:29 +08:00
# include "config.h"
2018-02-11 00:49:15 +08:00
# include "logs.h"
2018-02-10 12:25:55 +08:00
# include "macros.h"
2018-02-10 01:26:16 +08:00
# include "mnt.h"
2018-02-10 01:08:11 +08:00
# include "user.h"
2018-02-10 01:45:50 +08:00
# include "util.h"
2018-02-09 22:44:29 +08:00
namespace cmdline {
2015-05-15 05:44:48 +08:00
2018-02-11 00:49:15 +08:00
# define _LOG_DEFAULT_FILE " / var / log / nsjail.log"
2015-05-15 05:44:48 +08:00
struct custom_option {
struct option opt ;
2017-10-09 05:00:45 +08:00
const char * descr ;
2015-05-15 05:44:48 +08:00
} ;
2017-10-09 04:52:52 +08:00
// clang-format off
2017-05-11 22:17:54 +08:00
struct custom_option custom_opts [ ] = {
2017-09-14 04:03:21 +08:00
{ { " help " , no_argument , NULL , ' h ' } , " Help plz.. " } ,
{ { " mode " , required_argument , NULL , ' M ' } ,
2017-09-30 04:18:16 +08:00
" Execution mode (default: 'o' [MODE_STANDALONE_ONCE]): \n "
" \t l: Wait for connections on a TCP port (specified with --port) [MODE_LISTEN_TCP] \n "
" \t o: Launch a single process on the console using clone/execve [MODE_STANDALONE_ONCE] \n "
" \t e: Launch a single process on the console using execve [MODE_STANDALONE_EXECVE] \n "
" \t r: Launch a single process on the console with clone/execve, keep doing it forever [MODE_STANDALONE_RERUN] " } ,
2017-09-26 15:30:03 +08:00
{ { " config " , required_argument , NULL , ' C ' } , " Configuration file in the config.proto ProtoBuf format (see configs/ directory for examples) " } ,
2017-09-14 04:03:21 +08:00
{ { " exec_file " , required_argument , NULL , ' x ' } , " File to exec (default: argv[0]) " } ,
2017-10-18 23:57:52 +08:00
{ { " execute_fd " , no_argument , NULL , 0x0607 } , " Use execveat() to execute a file-descriptor instead of executing the binary path. In such case argv[0]/exec_file denotes a file path before mount namespacing " } ,
2017-09-14 04:03:21 +08:00
{ { " chroot " , required_argument , NULL , ' c ' } , " Directory containing / of the jail (default: none) " } ,
2017-10-11 08:16:14 +08:00
{ { " rw " , no_argument , NULL , 0x601 } , " Mount chroot dir (/) R/W (default: R/O) " } ,
2017-09-14 04:03:21 +08:00
{ { " user " , required_argument , NULL , ' u ' } , " Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid:count convention here. Can be specified multiple times " } ,
{ { " group " , required_argument , NULL , ' g ' } , " Groupname/gid of processess inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid:count convention here. Can be specified multiple times " } ,
{ { " hostname " , required_argument , NULL , ' H ' } , " UTS name (hostname) of the jail (default: 'NSJAIL') " } ,
{ { " cwd " , required_argument , NULL , ' D ' } , " Directory in the namespace the process will run (default: '/') " } ,
{ { " port " , required_argument , NULL , ' p ' } , " TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0) " } ,
{ { " bindhost " , required_argument , NULL , 0x604 } , " IP address to bind the port to (only in [MODE_LISTEN_TCP]), (default: '::') " } ,
{ { " max_conns_per_ip " , required_argument , NULL , ' i ' } , " Maximum number of connections per one IP (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited)) " } ,
{ { " log " , required_argument , NULL , ' l ' } , " Log file (default: use log_fd) " } ,
{ { " log_fd " , required_argument , NULL , ' L ' } , " Log FD (default: 2) " } ,
{ { " time_limit " , required_argument , NULL , ' t ' } , " Maximum time that a jail can exist, in seconds (default: 600) " } ,
{ { " max_cpus " , required_argument , NULL , 0x508 } , " Maximum number of CPUs a single jailed process can use (default: 0 'no limit') " } ,
{ { " daemon " , no_argument , NULL , ' d ' } , " Daemonize after start " } ,
{ { " verbose " , no_argument , NULL , ' v ' } , " Verbose output " } ,
2017-10-07 08:03:51 +08:00
{ { " quiet " , no_argument , NULL , ' q ' } , " Log warning and more important messages only " } ,
{ { " really_quiet " , no_argument , NULL , ' Q ' } , " Log fatal messages only " } ,
2017-10-07 18:31:54 +08:00
{ { " keep_env " , no_argument , NULL , ' e ' } , " Pass all environment variables to the child process (default: all envvars are cleared) " } ,
2017-09-30 04:18:16 +08:00
{ { " env " , required_argument , NULL , ' E ' } , " Additional environment variable (can be used multiple times) " } ,
2017-10-07 18:31:54 +08:00
{ { " keep_caps " , no_argument , NULL , 0x0501 } , " Don't drop any capabilities " } ,
{ { " cap " , required_argument , NULL , 0x0509 } , " Retain this capability, e.g. CAP_PTRACE (can be specified multiple times) " } ,
{ { " silent " , no_argument , NULL , 0x0502 } , " Redirect child process' fd:0/1/2 to /dev/null " } ,
2017-11-02 20:13:07 +08:00
{ { " skip_setsid " , no_argument , NULL , 0x0504 } , " Don't call setsid(), allows for terminal signal handling in the sandboxed process. Dangerous " } ,
2017-10-07 18:31:54 +08:00
{ { " pass_fd " , required_argument , NULL , 0x0505 } , " Don't close this FD before executing the child process (can be specified multiple times), by default: 0/1/2 are kept open " } ,
2017-09-14 04:03:21 +08:00
{ { " disable_no_new_privs " , no_argument , NULL , 0x0507 } , " Don't set the prctl(NO_NEW_PRIVS, 1) (DANGEROUS) " } ,
2017-10-07 18:33:19 +08:00
{ { " rlimit_as " , required_argument , NULL , 0x0201 } , " RLIMIT_AS in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM64_INFINITY (default: 512) " } ,
{ { " rlimit_core " , required_argument , NULL , 0x0202 } , " RLIMIT_CORE in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM64_INFINITY (default: 0) " } ,
{ { " rlimit_cpu " , required_argument , NULL , 0x0203 } , " RLIMIT_CPU, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM64_INFINITY (default: 600) " } ,
{ { " rlimit_fsize " , required_argument , NULL , 0x0204 } , " RLIMIT_FSIZE in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM64_INFINITY (default: 1) " } ,
{ { " rlimit_nofile " , required_argument , NULL , 0x0205 } , " RLIMIT_NOFILE, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM64_INFINITY (default: 32) " } ,
{ { " rlimit_nproc " , required_argument , NULL , 0x0206 } , " RLIMIT_NPROC, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM64_INFINITY (default: 'soft') " } ,
2017-10-08 19:00:37 +08:00
{ { " rlimit_stack " , required_argument , NULL , 0x0207 } , " RLIMIT_STACK in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM64_INFINITY (default: 'soft') " } ,
2017-09-14 04:03:21 +08:00
{ { " persona_addr_compat_layout " , no_argument , NULL , 0x0301 } , " personality(ADDR_COMPAT_LAYOUT) " } ,
{ { " persona_mmap_page_zero " , no_argument , NULL , 0x0302 } , " personality(MMAP_PAGE_ZERO) " } ,
{ { " persona_read_implies_exec " , no_argument , NULL , 0x0303 } , " personality(READ_IMPLIES_EXEC) " } ,
{ { " persona_addr_limit_3gb " , no_argument , NULL , 0x0304 } , " personality(ADDR_LIMIT_3GB) " } ,
{ { " persona_addr_no_randomize " , no_argument , NULL , 0x0305 } , " personality(ADDR_NO_RANDOMIZE) " } ,
2017-09-30 04:18:16 +08:00
{ { " disable_clone_newnet " , no_argument , NULL , ' N ' } , " Don't use CLONE_NEWNET. Enable global networking inside the jail " } ,
2017-09-14 04:03:21 +08:00
{ { " disable_clone_newuser " , no_argument , NULL , 0x0402 } , " Don't use CLONE_NEWUSER. Requires euid==0 " } ,
{ { " disable_clone_newns " , no_argument , NULL , 0x0403 } , " Don't use CLONE_NEWNS " } ,
{ { " disable_clone_newpid " , no_argument , NULL , 0x0404 } , " Don't use CLONE_NEWPID " } ,
{ { " disable_clone_newipc " , no_argument , NULL , 0x0405 } , " Don't use CLONE_NEWIPC " } ,
{ { " disable_clone_newuts " , no_argument , NULL , 0x0406 } , " Don't use CLONE_NEWUTS " } ,
2017-10-26 22:16:05 +08:00
{ { " disable_clone_newcgroup " , no_argument , NULL , 0x0407 } , " Don't use CLONE_NEWCGROUP. Might be required for kernel versions < 4.6 " } ,
2017-09-30 04:18:16 +08:00
{ { " uid_mapping " , required_argument , NULL , ' U ' } , " Add a custom uid mapping of the form inside_uid:outside_uid:count. Setting this requires newuidmap (set-uid) to be present " } ,
{ { " gid_mapping " , required_argument , NULL , ' G ' } , " Add a custom gid mapping of the form inside_gid:outside_gid:count. Setting this requires newgidmap (set-uid) to be present " } ,
2017-09-14 04:03:21 +08:00
{ { " 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' " } ,
{ { " 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' " } ,
2017-10-11 08:16:14 +08:00
{ { " tmpfsmount " , required_argument , NULL , ' T ' } , " List of mountpoints to be mounted as tmpfs (R/W) inside the container. Can be specified multiple times. Supports 'dest' syntax " } ,
2017-09-14 04:03:21 +08:00
{ { " tmpfs_size " , required_argument , NULL , 0x0602 } , " Number of bytes to allocate for tmpfsmounts (default: 4194304) " } ,
2018-02-11 22:07:24 +08:00
{ { " mount " , required_argument , NULL , ' m ' } , " Arbitrary mount, format src:dst:fs_type:options " } ,
2017-10-11 08:10:52 +08:00
{ { " disable_proc " , no_argument , NULL , 0x0603 } , " Disable mounting procfs in the jail " } ,
{ { " proc_path " , required_argument , NULL , 0x0605 } , " Path used to mount procfs (default: '/proc') " } ,
{ { " proc_rw " , no_argument , NULL , 0x0606 } , " Is procfs mounted as R/W (default: R/O) " } ,
2017-09-14 04:03:21 +08:00
{ { " seccomp_policy " , required_argument , NULL , ' P ' } , " Path to file containing seccomp-bpf policy (see kafel/) " } ,
{ { " seccomp_string " , required_argument , NULL , 0x0901 } , " String with kafel seccomp-bpf policy (see kafel/) " } ,
{ { " cgroup_mem_max " , required_argument , NULL , 0x0801 } , " Maximum number of bytes to use in the group (default: '0' - disabled) " } ,
{ { " cgroup_mem_mount " , required_argument , NULL , 0x0802 } , " Location of memory cgroup FS (default: '/sys/fs/cgroup/memory') " } ,
{ { " cgroup_mem_parent " , required_argument , NULL , 0x0803 } , " Which pre-existing memory cgroup to use as a parent (default: 'NSJAIL') " } ,
{ { " cgroup_pids_max " , required_argument , NULL , 0x0811 } , " Maximum number of pids in a cgroup (default: '0' - disabled) " } ,
{ { " cgroup_pids_mount " , required_argument , NULL , 0x0812 } , " Location of pids cgroup FS (default: '/sys/fs/cgroup/pids') " } ,
{ { " cgroup_pids_parent " , required_argument , NULL , 0x0813 } , " Which pre-existing pids cgroup to use as a parent (default: 'NSJAIL') " } ,
2017-10-25 16:15:03 +08:00
{ { " cgroup_net_cls_classid " , required_argument , NULL , 0x0821 } , " Class identifier of network packets in the group (default: '0' - disabled) " } ,
{ { " cgroup_net_cls_mount " , required_argument , NULL , 0x0822 } , " Location of net_cls cgroup FS (default: '/sys/fs/cgroup/net_cls') " } ,
{ { " cgroup_net_cls_parent " , required_argument , NULL , 0x0823 } , " Which pre-existing net_cls cgroup to use as a parent (default: 'NSJAIL') " } ,
2018-02-04 11:15:19 +08:00
{ { " cgroup_cpu_ms_per_sec " , required_argument , NULL , 0x0831 } , " Number of us that the process group can use per second (default: '0' - disabled) " } ,
{ { " cgroup_cpu_mount " , required_argument , NULL , 0x0822 } , " Location of cpu cgroup FS (default: '/sys/fs/cgroup/net_cls') " } ,
{ { " cgroup_cpu_parent " , required_argument , NULL , 0x0833 } , " Which pre-existing cpu cgroup to use as a parent (default: 'NSJAIL') " } ,
2017-09-30 04:18:16 +08:00
{ { " iface_no_lo " , no_argument , NULL , 0x700 } , " Don't bring the 'lo' interface up " } ,
2017-09-14 04:03:21 +08:00
{ { " macvlan_iface " , required_argument , NULL , ' I ' } , " Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs' " } ,
{ { " macvlan_vs_ip " , required_argument , NULL , 0x701 } , " IP of the 'vs' interface (e.g. \" 192.168.0.1 \" ) " } ,
{ { " macvlan_vs_nm " , required_argument , NULL , 0x702 } , " Netmask of the 'vs' interface (e.g. \" 255.255.255.0 \" ) " } ,
{ { " macvlan_vs_gw " , required_argument , NULL , 0x703 } , " Default GW for the 'vs' interface (e.g. \" 192.168.0.1 \" ) " } ,
2017-05-11 22:17:54 +08:00
} ;
struct custom_option deprecated_opts [ ] = {
// Compatibilty flags for MACVLAN.
// TODO(rswiecki): Remove this at some point.
2017-09-14 04:03:21 +08:00
{ { " iface " , required_argument , NULL , ' I ' } , " Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs' " } ,
{ { " iface_vs_ip " , required_argument , NULL , 0x701 } , " IP of the 'vs' interface (e.g. \" 192.168.0.1 \" ) " } ,
{ { " iface_vs_nm " , required_argument , NULL , 0x702 } , " Netmask of the 'vs' interface (e.g. \" 255.255.255.0 \" ) " } ,
{ { " iface_vs_gw " , required_argument , NULL , 0x703 } , " Default GW for the 'vs' interface (e.g. \" 192.168.0.1 \" ) " } ,
2017-10-26 22:16:05 +08:00
{ { " enable_clone_newcgroup " , no_argument , NULL , 0x0408 } , " Use CLONE_NEWCGROUP (it's enabled by default now) " } ,
2017-05-11 22:17:54 +08:00
} ;
2017-10-09 04:52:52 +08:00
// clang-format on
2017-05-11 22:17:54 +08:00
2018-02-11 03:32:04 +08:00
static const char * logYesNo ( bool yes ) {
return ( yes ? " true " : " false " ) ;
}
2015-05-15 05:44:48 +08:00
2017-10-26 06:26:02 +08:00
static void cmdlineOptUsage ( struct custom_option * option ) {
2017-05-11 22:17:54 +08:00
if ( option - > opt . val < 0x80 ) {
LOG_HELP_BOLD ( " --%s%s%c %s " , option - > opt . name , " |- " , option - > opt . val ,
2017-10-09 05:00:45 +08:00
option - > opt . has_arg = = required_argument ? " VALUE " : " " ) ;
2017-05-11 22:17:54 +08:00
} else {
LOG_HELP_BOLD ( " --%s %s " , option - > opt . name ,
2017-10-09 05:00:45 +08:00
option - > opt . has_arg = = required_argument ? " VALUE " : " " ) ;
2017-05-11 22:17:54 +08:00
}
LOG_HELP ( " \t %s " , option - > descr ) ;
}
2017-10-26 06:26:02 +08:00
static void cmdlineUsage ( const char * pname ) {
2015-05-15 05:44:48 +08:00
LOG_HELP_BOLD ( " Usage: %s [options] -- path_to_command [args] " , pname ) ;
LOG_HELP_BOLD ( " Options: " ) ;
2017-05-11 22:17:54 +08:00
for ( size_t i = 0 ; i < ARRAYSIZE ( custom_opts ) ; i + + ) {
cmdlineOptUsage ( & custom_opts [ i ] ) ;
}
LOG_HELP_BOLD ( " \n Deprecated options: " ) ;
for ( size_t i = 0 ; i < ARRAYSIZE ( deprecated_opts ) ; i + + ) {
cmdlineOptUsage ( & deprecated_opts [ i ] ) ;
// Find replacement flag.
for ( size_t j = 0 ; j < ARRAYSIZE ( custom_opts ) ; j + + ) {
if ( custom_opts [ j ] . opt . val = = deprecated_opts [ i ] . opt . val ) {
2017-10-17 21:22:23 +08:00
LOG_HELP_BOLD (
" \t DEPRECATED: Use %s instead. " , custom_opts [ j ] . opt . name ) ;
2017-05-11 22:17:54 +08:00
break ;
}
2015-05-15 05:44:48 +08:00
}
}
2016-05-10 06:54:25 +08:00
LOG_HELP_BOLD ( " \n Examples: " ) ;
LOG_HELP ( " Wait on a port 31337 for connections, and run /bin/sh " ) ;
LOG_HELP_BOLD ( " nsjail -Ml --port 31337 --chroot / -- /bin/sh -i " ) ;
LOG_HELP ( " Re-run echo command as a sub-process " ) ;
LOG_HELP_BOLD ( " nsjail -Mr --chroot / -- /bin/echo \" ABC \" " ) ;
LOG_HELP ( " Run echo command once only, as a sub-process " ) ;
LOG_HELP_BOLD ( " nsjail -Mo --chroot / -- /bin/echo \" ABC \" " ) ;
2016-05-10 21:54:10 +08:00
LOG_HELP ( " Execute echo command directly, without a supervising process " ) ;
LOG_HELP_BOLD ( " nsjail -Me --chroot / --disable_proc -- /bin/echo \" ABC \" " ) ;
2015-05-15 05:44:48 +08:00
}
2018-02-10 22:50:12 +08:00
void logParams ( nsjconf_t * nsjconf ) {
2015-05-15 05:44:48 +08:00
switch ( nsjconf - > mode ) {
case MODE_LISTEN_TCP :
LOG_I ( " Mode: LISTEN_TCP " ) ;
break ;
case MODE_STANDALONE_ONCE :
LOG_I ( " Mode: STANDALONE_ONCE " ) ;
break ;
2015-08-15 22:02:38 +08:00
case MODE_STANDALONE_EXECVE :
LOG_I ( " Mode: STANDALONE_EXECVE " ) ;
break ;
2015-05-15 05:44:48 +08:00
case MODE_STANDALONE_RERUN :
LOG_I ( " Mode: STANDALONE_RERUN " ) ;
break ;
default :
LOG_F ( " Mode: UNKNOWN " ) ;
break ;
}
2017-10-26 06:26:02 +08:00
LOG_I (
" Jail parameters: hostname:'%s', chroot:'%s', process:'%s', "
" bind:[%s]:%d, "
" max_conns_per_ip:%u, time_limit:%ld, personality:%#lx, daemonize:%s, "
" clone_newnet:%s, clone_newuser:%s, clone_newns:%s, clone_newpid:%s, "
" clone_newipc:%s, clonew_newuts:%s, clone_newcgroup:%s, keep_caps:%s, "
" tmpfs_size:%zu, disable_no_new_privs:%s, max_cpus:%zu " ,
2018-02-12 23:52:05 +08:00
nsjconf - > hostname . c_str ( ) , nsjconf - > chroot . c_str ( ) , nsjconf - > argv [ 0 ] . c_str ( ) ,
2018-02-11 06:46:15 +08:00
nsjconf - > bindhost . c_str ( ) , nsjconf - > port , nsjconf - > max_conns_per_ip , nsjconf - > tlimit ,
nsjconf - > personality , logYesNo ( nsjconf - > daemonize ) , logYesNo ( nsjconf - > clone_newnet ) ,
2017-10-09 05:00:45 +08:00
logYesNo ( nsjconf - > clone_newuser ) , logYesNo ( nsjconf - > clone_newns ) ,
logYesNo ( nsjconf - > clone_newpid ) , logYesNo ( nsjconf - > clone_newipc ) ,
logYesNo ( nsjconf - > clone_newuts ) , logYesNo ( nsjconf - > clone_newcgroup ) ,
logYesNo ( nsjconf - > keep_caps ) , nsjconf - > tmpfs_size ,
logYesNo ( nsjconf - > disable_no_new_privs ) , nsjconf - > max_cpus ) ;
2015-06-18 09:00:39 +08:00
2018-02-11 06:46:15 +08:00
for ( const auto & p : nsjconf - > mountpts ) {
2018-02-12 06:44:43 +08:00
LOG_I ( " %s: %s " , p . is_symlink ? " Symlink " : " Mount point " ,
2018-02-11 07:24:43 +08:00
mnt : : describeMountPt ( p ) . c_str ( ) ) ;
2016-09-25 20:30:19 +08:00
}
2018-02-11 06:46:15 +08:00
for ( const auto & uid : nsjconf - > uids ) {
LOG_I ( " Uid map: inside_uid:%lu outside_uid:%lu count:%zu newuidmap:%s " ,
( unsigned long ) uid . inside_id , ( unsigned long ) uid . outside_id , uid . count ,
uid . is_newidmap ? " true " : " false " ) ;
if ( uid . outside_id = = 0 & & nsjconf - > clone_newuser ) {
LOG_W (
" Process will be UID/EUID=0 in the global user namespace, "
" and will have user "
" root-level access to files " ) ;
2017-02-08 07:36:32 +08:00
}
2018-02-11 06:46:15 +08:00
}
for ( const auto & gid : nsjconf - > gids ) {
LOG_I ( " Gid map: inside_gid:%lu outside_gid:%lu count:%zu newgidmap:%s " ,
( unsigned long ) gid . inside_id , ( unsigned long ) gid . outside_id , gid . count ,
gid . is_newidmap ? " true " : " false " ) ;
if ( gid . outside_id = = 0 & & nsjconf - > clone_newuser ) {
LOG_W (
" Process will be GID/EGID=0 in the global user namespace, "
" and will have group "
" root-level access to files " ) ;
2016-09-25 20:30:19 +08:00
}
2015-05-15 05:44:48 +08:00
}
}
2018-02-09 22:44:29 +08:00
uint64_t parseRLimit ( int res , const char * optarg , unsigned long mul ) {
2017-10-07 18:37:26 +08:00
if ( strcasecmp ( optarg , " inf " ) = = 0 ) {
return RLIM64_INFINITY ;
}
2015-10-14 01:06:49 +08:00
struct rlimit64 cur ;
2017-09-29 20:11:48 +08:00
if ( getrlimit64 ( res , & cur ) = = - 1 ) {
2015-05-15 05:44:48 +08:00
PLOG_F ( " getrlimit(%d) " , res ) ;
}
2017-10-07 04:44:27 +08:00
if ( strcasecmp ( optarg , " def " ) = = 0 | | strcasecmp ( optarg , " soft " ) = = 0 ) {
return cur . rlim_cur ;
}
2017-10-08 18:57:43 +08:00
if ( strcasecmp ( optarg , " max " ) = = 0 | | strcasecmp ( optarg , " hard " ) = = 0 ) {
2015-05-15 05:44:48 +08:00
return cur . rlim_max ;
}
2018-02-12 22:17:33 +08:00
if ( ! util : : isANumber ( optarg ) ) {
2017-10-26 06:26:02 +08:00
LOG_F (
" RLIMIT %d needs a numeric or 'max'/'hard'/'def'/'soft'/'inf' value ('%s' "
" provided) " ,
2017-10-09 05:00:45 +08:00
res , optarg ) ;
2015-05-15 05:44:48 +08:00
}
2017-10-25 21:44:35 +08:00
uint64_t val = strtoull ( optarg , NULL , 0 ) * mul ;
2015-10-14 01:06:49 +08:00
if ( val = = ULLONG_MAX & & errno ! = 0 ) {
2015-05-15 05:44:48 +08:00
PLOG_F ( " strtoul('%s', 0) " , optarg ) ;
}
return val ;
}
2018-02-11 21:56:30 +08:00
static std : : string argByColon ( const char * str , size_t pos ) {
if ( ! str ) {
return " " ;
2017-05-27 05:07:47 +08:00
}
2018-02-11 21:56:30 +08:00
std : : vector < std : : string > vec ;
util : : strSplit ( str , & vec , ' : ' ) ;
2018-02-11 22:07:24 +08:00
if ( pos > = vec . size ( ) ) {
2018-02-11 21:56:30 +08:00
return " " ;
2016-01-23 14:05:24 +08:00
}
2018-02-11 21:56:30 +08:00
return vec [ pos ] ;
2016-01-23 14:05:24 +08:00
}
2018-02-10 22:50:12 +08:00
std : : unique_ptr < nsjconf_t > parseArgs ( int argc , char * argv [ ] ) {
std : : unique_ptr < nsjconf_t > nsjconf = std : : make_unique < nsjconf_t > ( ) ;
2018-02-09 22:44:29 +08:00
nsjconf - > use_execveat = false ;
nsjconf - > exec_fd = - 1 ;
nsjconf - > hostname = " NSJAIL " ;
nsjconf - > cwd = " / " ;
nsjconf - > port = 0 ;
nsjconf - > bindhost = " :: " ;
2018-02-11 00:49:15 +08:00
nsjconf - > loglevel = logs : : INFO ;
2018-02-09 22:44:29 +08:00
nsjconf - > daemonize = false ;
nsjconf - > tlimit = 0 ;
nsjconf - > max_cpus = 0 ;
nsjconf - > keep_caps = false ;
nsjconf - > disable_no_new_privs = false ;
nsjconf - > rl_as = 512 * ( 1024 * 1024 ) ;
nsjconf - > rl_core = 0 ;
nsjconf - > rl_cpu = 600 ;
nsjconf - > rl_fsize = 1 * ( 1024 * 1024 ) ;
nsjconf - > rl_nofile = 32 ;
nsjconf - > rl_nproc = parseRLimit ( RLIMIT_NPROC , " soft " , 1 ) ;
nsjconf - > rl_stack = parseRLimit ( RLIMIT_STACK , " soft " , 1 ) ;
nsjconf - > personality = 0 ;
nsjconf - > clone_newnet = true ;
nsjconf - > clone_newuser = true ;
nsjconf - > clone_newns = true ;
nsjconf - > clone_newpid = true ;
nsjconf - > clone_newipc = true ;
nsjconf - > clone_newuts = true ;
nsjconf - > clone_newcgroup = true ;
nsjconf - > mode = MODE_STANDALONE_ONCE ;
nsjconf - > is_root_rw = false ;
nsjconf - > is_silent = false ;
nsjconf - > skip_setsid = false ;
nsjconf - > max_conns_per_ip = 0 ;
nsjconf - > tmpfs_size = 4 * ( 1024 * 1024 ) ;
nsjconf - > proc_path = " /proc " ;
nsjconf - > is_proc_rw = false ;
nsjconf - > cgroup_mem_mount = " /sys/fs/cgroup/memory " ;
nsjconf - > cgroup_mem_parent = " NSJAIL " ;
nsjconf - > cgroup_mem_max = ( size_t ) 0 ;
nsjconf - > cgroup_pids_mount = " /sys/fs/cgroup/pids " ;
nsjconf - > cgroup_pids_parent = " NSJAIL " ;
nsjconf - > cgroup_pids_max = 0U ;
nsjconf - > cgroup_net_cls_mount = " /sys/fs/cgroup/net_cls " ;
nsjconf - > cgroup_net_cls_parent = " NSJAIL " ;
nsjconf - > cgroup_net_cls_classid = 0U ;
nsjconf - > cgroup_cpu_mount = " /sys/fs/cgroup/cpu " ;
nsjconf - > cgroup_cpu_parent = " NSJAIL " ;
nsjconf - > cgroup_cpu_ms_per_sec = 0U ;
2018-02-11 01:22:51 +08:00
nsjconf - > iface_lo = true ;
2018-02-09 22:44:29 +08:00
nsjconf - > iface_vs_ip = " 0.0.0.0 " ;
nsjconf - > iface_vs_nm = " 255.255.255.0 " ;
nsjconf - > iface_vs_gw = " 0.0.0.0 " ;
nsjconf - > orig_uid = getuid ( ) ;
nsjconf - > num_cpus = sysconf ( _SC_NPROCESSORS_ONLN ) ;
2018-02-13 00:31:45 +08:00
nsjconf - > seccomp_fprog . filter = NULL ;
nsjconf - > seccomp_fprog . len = 0 ;
2015-06-17 22:52:51 +08:00
2018-02-10 05:47:00 +08:00
nsjconf - > openfds . push_back ( STDIN_FILENO ) ;
nsjconf - > openfds . push_back ( STDOUT_FILENO ) ;
nsjconf - > openfds . push_back ( STDERR_FILENO ) ;
2015-10-17 22:48:30 +08:00
static char cmdlineTmpfsSz [ PATH_MAX ] = " size=4194304 " ;
2015-05-15 05:44:48 +08:00
2017-05-11 22:17:54 +08:00
// Generate options array for getopt_long.
size_t options_length = ARRAYSIZE ( custom_opts ) + ARRAYSIZE ( deprecated_opts ) + 1 ;
struct option opts [ options_length ] ;
2015-05-15 05:44:48 +08:00
for ( unsigned i = 0 ; i < ARRAYSIZE ( custom_opts ) ; i + + ) {
opts [ i ] = custom_opts [ i ] . opt ;
}
2017-05-11 22:17:54 +08:00
for ( unsigned i = 0 ; i < ARRAYSIZE ( deprecated_opts ) ; i + + ) {
opts [ ARRAYSIZE ( custom_opts ) + i ] = deprecated_opts [ i ] . opt ;
}
// Last, NULL option as a terminator.
2017-10-26 06:26:02 +08:00
struct option terminator = { NULL , 0 , NULL , 0 } ;
2017-05-11 22:17:54 +08:00
memcpy ( & opts [ options_length - 1 ] . name , & terminator , sizeof ( terminator ) ) ;
2015-05-15 05:44:48 +08:00
int opt_index = 0 ;
for ( ; ; ) {
2017-05-11 22:17:54 +08:00
int c = getopt_long ( argc , argv ,
2018-02-11 22:07:24 +08:00
" x:H:D:C:c:p:i:u:g:l:L:t:M:NdvqQeh?E:R:B:T:m:P:I:U:G: " , opts , & opt_index ) ;
2015-05-15 05:44:48 +08:00
if ( c = = - 1 ) {
break ;
}
switch ( c ) {
2017-06-09 07:57:04 +08:00
case ' x ' :
nsjconf - > exec_file = optarg ;
break ;
2015-05-15 05:44:48 +08:00
case ' H ' :
nsjconf - > hostname = optarg ;
break ;
2015-11-07 20:01:44 +08:00
case ' D ' :
nsjconf - > cwd = optarg ;
break ;
2017-05-26 07:44:16 +08:00
case ' C ' :
2018-02-12 22:17:33 +08:00
if ( ! config : : parseFile ( nsjconf . get ( ) , optarg ) ) {
2017-05-26 07:44:16 +08:00
LOG_F ( " Couldn't parse configuration from '%s' file " , optarg ) ;
}
break ;
2015-05-15 05:44:48 +08:00
case ' c ' :
nsjconf - > chroot = optarg ;
break ;
case ' p ' :
nsjconf - > port = strtoul ( optarg , NULL , 0 ) ;
2016-08-19 03:31:07 +08:00
nsjconf - > mode = MODE_LISTEN_TCP ;
2015-05-15 05:44:48 +08:00
break ;
2016-02-26 01:27:48 +08:00
case 0x604 :
nsjconf - > bindhost = optarg ;
break ;
2015-05-15 05:44:48 +08:00
case ' i ' :
nsjconf - > max_conns_per_ip = strtoul ( optarg , NULL , 0 ) ;
break ;
case ' l ' :
2017-05-26 11:12:01 +08:00
nsjconf - > logfile = optarg ;
2015-05-15 05:44:48 +08:00
break ;
2017-06-12 06:06:13 +08:00
case ' L ' :
2018-02-12 10:05:21 +08:00
nsjconf - > logfile =
" /dev/fd/ " + std : : to_string ( std : : strtol ( optarg , NULL , 10 ) ) ;
2017-06-12 06:06:13 +08:00
break ;
2015-05-15 05:44:48 +08:00
case ' d ' :
nsjconf - > daemonize = true ;
break ;
case ' v ' :
2018-02-11 00:49:15 +08:00
nsjconf - > loglevel = logs : : DEBUG ;
2018-02-12 10:11:58 +08:00
logs : : logLevel ( nsjconf - > loglevel ) ;
2017-02-15 04:54:02 +08:00
break ;
case ' q ' :
2018-02-11 00:49:15 +08:00
nsjconf - > loglevel = logs : : WARNING ;
2018-02-12 10:11:58 +08:00
logs : : logLevel ( nsjconf - > loglevel ) ;
2015-05-15 05:44:48 +08:00
break ;
2017-10-07 08:03:51 +08:00
case ' Q ' :
2018-02-11 00:49:15 +08:00
nsjconf - > loglevel = logs : : FATAL ;
2018-02-12 10:11:58 +08:00
logs : : logLevel ( nsjconf - > loglevel ) ;
2017-10-07 08:03:51 +08:00
break ;
2015-05-15 05:44:48 +08:00
case ' e ' :
nsjconf - > keep_env = true ;
break ;
case ' t ' :
nsjconf - > tlimit = strtol ( optarg , NULL , 0 ) ;
break ;
2017-10-09 05:00:45 +08:00
case ' h ' : /* help */
2017-05-11 22:17:54 +08:00
cmdlineUsage ( argv [ 0 ] ) ;
2017-02-16 09:22:37 +08:00
exit ( 0 ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0201 :
2018-02-09 22:44:29 +08:00
nsjconf - > rl_as = parseRLimit ( RLIMIT_AS , optarg , ( 1024 * 1024 ) ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0202 :
2018-02-09 22:44:29 +08:00
nsjconf - > rl_core = parseRLimit ( RLIMIT_CORE , optarg , ( 1024 * 1024 ) ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0203 :
2018-02-09 22:44:29 +08:00
nsjconf - > rl_cpu = parseRLimit ( RLIMIT_CPU , optarg , 1 ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0204 :
2018-02-09 22:44:29 +08:00
nsjconf - > rl_fsize = parseRLimit ( RLIMIT_FSIZE , optarg , ( 1024 * 1024 ) ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0205 :
2018-02-09 22:44:29 +08:00
nsjconf - > rl_nofile = parseRLimit ( RLIMIT_NOFILE , optarg , 1 ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0206 :
2018-02-09 22:44:29 +08:00
nsjconf - > rl_nproc = parseRLimit ( RLIMIT_NPROC , optarg , 1 ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0207 :
2018-02-09 22:44:29 +08:00
nsjconf - > rl_stack = parseRLimit ( RLIMIT_STACK , optarg , ( 1024 * 1024 ) ) ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0301 :
nsjconf - > personality | = ADDR_COMPAT_LAYOUT ;
break ;
case 0x0302 :
nsjconf - > personality | = MMAP_PAGE_ZERO ;
break ;
case 0x0303 :
nsjconf - > personality | = READ_IMPLIES_EXEC ;
break ;
case 0x0304 :
nsjconf - > personality | = ADDR_LIMIT_3GB ;
break ;
case 0x0305 :
nsjconf - > personality | = ADDR_NO_RANDOMIZE ;
break ;
case ' N ' :
nsjconf - > clone_newnet = false ;
break ;
case 0x0402 :
nsjconf - > clone_newuser = false ;
break ;
case 0x0403 :
nsjconf - > clone_newns = false ;
break ;
case 0x0404 :
nsjconf - > clone_newpid = false ;
break ;
case 0x0405 :
nsjconf - > clone_newipc = false ;
break ;
case 0x0406 :
nsjconf - > clone_newuts = false ;
break ;
2016-06-19 17:55:55 +08:00
case 0x0407 :
2017-10-26 22:16:05 +08:00
nsjconf - > clone_newcgroup = false ;
break ;
case 0x0408 :
2016-06-19 17:55:55 +08:00
nsjconf - > clone_newcgroup = true ;
break ;
2015-05-15 05:44:48 +08:00
case 0x0501 :
2017-07-05 23:29:57 +08:00
nsjconf - > keep_caps = true ;
2015-05-15 05:44:48 +08:00
break ;
case 0x0502 :
2015-08-15 22:02:38 +08:00
nsjconf - > is_silent = true ;
2015-05-15 05:44:48 +08:00
break ;
2016-01-26 01:09:32 +08:00
case 0x0504 :
nsjconf - > skip_setsid = true ;
break ;
2018-02-10 05:47:00 +08:00
case 0x0505 :
nsjconf - > openfds . push_back ( ( int ) strtol ( optarg , NULL , 0 ) ) ;
break ;
2016-09-25 21:56:28 +08:00
case 0x0507 :
nsjconf - > disable_no_new_privs = true ;
break ;
2017-06-19 23:01:50 +08:00
case 0x0508 :
2017-06-21 23:52:16 +08:00
nsjconf - > max_cpus = strtoul ( optarg , NULL , 0 ) ;
2017-06-19 23:01:50 +08:00
break ;
2017-10-18 23:57:52 +08:00
case 0x0509 : {
2018-02-10 05:35:33 +08:00
int cap = caps : : nameToVal ( optarg ) ;
if ( cap = = - 1 ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-07-05 19:03:14 +08:00
}
2018-02-10 05:35:33 +08:00
nsjconf - > caps . push_back ( cap ) ;
2017-10-09 05:00:45 +08:00
} break ;
2015-08-15 22:02:38 +08:00
case 0x0601 :
2015-05-15 05:44:48 +08:00
nsjconf - > is_root_rw = true ;
break ;
2015-08-15 22:02:38 +08:00
case 0x0602 :
nsjconf - > tmpfs_size = strtoull ( optarg , NULL , 0 ) ;
2015-10-17 22:48:30 +08:00
snprintf ( cmdlineTmpfsSz , sizeof ( cmdlineTmpfsSz ) , " size=%zu " ,
2017-10-09 05:00:45 +08:00
nsjconf - > tmpfs_size ) ;
2015-08-15 22:02:38 +08:00
break ;
case 0x0603 :
2018-02-11 03:16:17 +08:00
nsjconf - > proc_path . clear ( ) ;
2015-05-15 05:44:48 +08:00
break ;
2017-10-11 08:10:52 +08:00
case 0x0605 :
nsjconf - > proc_path = optarg ;
break ;
case 0x0606 :
nsjconf - > is_proc_rw = true ;
break ;
2017-10-18 23:57:52 +08:00
case 0x0607 :
nsjconf - > use_execveat = true ;
break ;
2018-02-10 06:04:57 +08:00
case ' E ' :
nsjconf - > envs . push_back ( optarg ) ;
break ;
2017-10-09 05:00:45 +08:00
case ' u ' : {
2018-02-11 21:56:30 +08:00
std : : string i_id = argByColon ( optarg , 0 ) ;
std : : string o_id = argByColon ( optarg , 1 ) ;
std : : string cnt = argByColon ( optarg , 2 ) ;
size_t count = std : : strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
if ( ! user : : parseId ( nsjconf . get ( ) , i_id , o_id , count , /* is_gid= */ false ,
/* is_newidmap= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-05-27 05:07:47 +08:00
}
2017-10-09 05:00:45 +08:00
} break ;
case ' g ' : {
2018-02-11 21:56:30 +08:00
std : : string i_id = argByColon ( optarg , 0 ) ;
std : : string o_id = argByColon ( optarg , 1 ) ;
std : : string cnt = argByColon ( optarg , 2 ) ;
size_t count = std : : strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
if ( ! user : : parseId ( nsjconf . get ( ) , i_id , o_id , count , /* is_gid= */ true ,
/* is_newidmap= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-05-27 05:07:47 +08:00
}
2017-10-09 05:00:45 +08:00
} break ;
case ' U ' : {
2018-02-11 21:56:30 +08:00
std : : string i_id = argByColon ( optarg , 0 ) ;
std : : string o_id = argByColon ( optarg , 1 ) ;
std : : string cnt = argByColon ( optarg , 2 ) ;
size_t count = std : : strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
if ( ! user : : parseId ( nsjconf . get ( ) , i_id , o_id , count , /* is_gid= */ false ,
/* is_newidmap= */ true ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-05-27 05:07:47 +08:00
}
2017-10-09 05:00:45 +08:00
} break ;
case ' G ' : {
2018-02-11 21:56:30 +08:00
std : : string i_id = argByColon ( optarg , 0 ) ;
std : : string o_id = argByColon ( optarg , 1 ) ;
std : : string cnt = argByColon ( optarg , 2 ) ;
size_t count = std : : strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
if ( ! user : : parseId ( nsjconf . get ( ) , i_id , o_id , count , /* is_gid= */ true ,
/* is_newidmap= */ true ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2016-09-25 20:30:19 +08:00
}
2017-10-09 05:00:45 +08:00
} break ;
case ' R ' : {
2018-02-11 21:56:30 +08:00
std : : string src = argByColon ( optarg , 0 ) ;
std : : string dst = argByColon ( optarg , 1 ) ;
if ( dst . empty ( ) ) {
dst = src ;
}
2018-02-12 06:44:43 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , src , dst , /* fs_type= */ " " ,
/* options= */ " " , MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY ,
/* is_dir= */ mnt : : NS_DIR_MAYBE , /* is_mandatory= */ true ,
/* src_env= */ " " , /* dst_env= */ " " , /* src_content= */ " " ,
/* is_symlink= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-10-09 05:00:45 +08:00
}
2017-10-17 21:22:23 +08:00
} ; break ;
2017-10-09 05:00:45 +08:00
case ' B ' : {
2018-02-11 21:56:30 +08:00
std : : string src = argByColon ( optarg , 0 ) ;
std : : string dst = argByColon ( optarg , 1 ) ;
if ( dst . empty ( ) ) {
dst = src ;
}
2018-02-12 06:44:43 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , src , dst , /* fs_type= */ " " ,
/* options= */ " " , MS_BIND | MS_REC | MS_PRIVATE ,
/* is_dir= */ mnt : : NS_DIR_MAYBE , /* is_mandatory= */ true ,
/* src_env= */ " " , /* dst_env= */ " " , /* src_content= */ " " ,
/* is_symlink= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-10-09 05:00:45 +08:00
}
2017-10-17 21:22:23 +08:00
} ; break ;
2017-10-09 05:00:45 +08:00
case ' T ' : {
2018-02-12 06:44:43 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , /* src= */ " " , optarg , " tmpfs " ,
2018-01-31 21:40:23 +08:00
/* options= */ cmdlineTmpfsSz , /* flags= */ 0 ,
2018-02-12 06:44:43 +08:00
/* is_dir= */ mnt : : NS_DIR_YES , /* is_mandatory= */ true ,
/* src_env= */ " " , /* dst_env= */ " " , /* src_content= */ " " ,
2017-10-17 21:22:23 +08:00
/* is_symlink= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-10-09 05:00:45 +08:00
}
2017-10-17 21:22:23 +08:00
} ; break ;
2018-02-11 22:07:24 +08:00
case ' m ' : {
std : : string src = argByColon ( optarg , 0 ) ;
std : : string dst = argByColon ( optarg , 1 ) ;
if ( dst . empty ( ) ) {
dst = src ;
}
std : : string fs_type = argByColon ( optarg , 2 ) ;
std : : string options = argByColon ( optarg , 3 ) ;
2018-02-12 06:44:43 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , src , dst , /* fs_type= */ fs_type ,
/* options= */ options , /* flags= */ 0 ,
/* is_dir= */ mnt : : NS_DIR_MAYBE , /* is_mandatory= */ true ,
/* src_env= */ " " , /* dst_env= */ " " , /* src_content= */ " " ,
/* is_symlink= */ false ) ) {
2018-02-11 22:07:24 +08:00
return nullptr ;
}
} ; break ;
2015-05-15 05:44:48 +08:00
case ' M ' :
switch ( optarg [ 0 ] ) {
case ' l ' :
nsjconf - > mode = MODE_LISTEN_TCP ;
break ;
case ' o ' :
nsjconf - > mode = MODE_STANDALONE_ONCE ;
break ;
2015-08-15 22:02:38 +08:00
case ' e ' :
nsjconf - > mode = MODE_STANDALONE_EXECVE ;
break ;
2015-05-15 05:44:48 +08:00
case ' r ' :
nsjconf - > mode = MODE_STANDALONE_RERUN ;
break ;
default :
LOG_E ( " Modes supported: -M l - MODE_LISTEN_TCP (default) " ) ;
LOG_E ( " -M o - MODE_STANDALONE_ONCE " ) ;
LOG_E ( " -M r - MODE_STANDALONE_RERUN " ) ;
2016-01-17 11:14:09 +08:00
LOG_E ( " -M e - MODE_STANDALONE_EXECVE " ) ;
2017-05-11 22:17:54 +08:00
cmdlineUsage ( argv [ 0 ] ) ;
2018-02-09 22:44:29 +08:00
return nullptr ;
2015-05-15 05:44:48 +08:00
break ;
}
break ;
2016-02-29 07:14:36 +08:00
case 0x700 :
2018-02-11 01:22:51 +08:00
nsjconf - > iface_lo = false ;
2016-02-29 09:51:55 +08:00
break ;
2016-02-29 22:36:31 +08:00
case ' I ' :
2017-06-13 04:20:21 +08:00
nsjconf - > iface_vs = optarg ;
2016-02-29 22:36:31 +08:00
break ;
2016-02-29 09:51:55 +08:00
case 0x701 :
nsjconf - > iface_vs_ip = optarg ;
break ;
case 0x702 :
nsjconf - > iface_vs_nm = optarg ;
break ;
case 0x703 :
nsjconf - > iface_vs_gw = optarg ;
2016-02-29 07:14:36 +08:00
break ;
2016-06-19 19:54:36 +08:00
case 0x801 :
2017-10-09 05:00:45 +08:00
nsjconf - > cgroup_mem_max = ( size_t ) strtoull ( optarg , NULL , 0 ) ;
2016-06-19 19:54:36 +08:00
break ;
case 0x802 :
2016-06-20 00:12:15 +08:00
nsjconf - > cgroup_mem_mount = optarg ;
2016-06-19 19:54:36 +08:00
break ;
case 0x803 :
2016-06-20 00:12:15 +08:00
nsjconf - > cgroup_mem_parent = optarg ;
2016-06-19 19:54:36 +08:00
break ;
2017-04-20 23:48:20 +08:00
case 0x811 :
2017-10-25 21:50:24 +08:00
nsjconf - > cgroup_pids_max = ( unsigned int ) strtoul ( optarg , NULL , 0 ) ;
2017-04-20 23:48:20 +08:00
break ;
case 0x812 :
nsjconf - > cgroup_pids_mount = optarg ;
break ;
case 0x813 :
nsjconf - > cgroup_pids_parent = optarg ;
break ;
2017-10-25 16:15:03 +08:00
case 0x821 :
nsjconf - > cgroup_net_cls_classid = ( unsigned int ) strtoul ( optarg , NULL , 0 ) ;
break ;
case 0x822 :
nsjconf - > cgroup_net_cls_mount = optarg ;
break ;
case 0x823 :
nsjconf - > cgroup_net_cls_parent = optarg ;
break ;
2018-02-04 11:15:19 +08:00
case 0x831 :
nsjconf - > cgroup_cpu_ms_per_sec = ( unsigned int ) strtoul ( optarg , NULL , 0 ) ;
break ;
case 0x832 :
nsjconf - > cgroup_cpu_mount = optarg ;
break ;
case 0x833 :
nsjconf - > cgroup_cpu_parent = optarg ;
break ;
2016-10-12 09:52:08 +08:00
case ' P ' :
2018-01-31 23:04:39 +08:00
nsjconf - > kafel_file_path = optarg ;
2016-09-13 18:10:15 +08:00
break ;
2018-02-11 06:46:15 +08:00
case 0x901 :
2016-10-12 09:52:08 +08:00
nsjconf - > kafel_string = optarg ;
break ;
2015-05-15 05:44:48 +08:00
default :
2017-05-11 22:17:54 +08:00
cmdlineUsage ( argv [ 0 ] ) ;
2018-02-09 22:44:29 +08:00
return nullptr ;
2015-05-15 05:44:48 +08:00
break ;
}
}
2018-02-11 00:49:15 +08:00
if ( nsjconf - > daemonize & & nsjconf - > logfile . empty ( ) ) {
nsjconf - > logfile = _LOG_DEFAULT_FILE ;
}
if ( ! logs : : initLog ( nsjconf - > logfile , nsjconf - > loglevel ) ) {
return nullptr ;
}
2018-02-11 03:16:17 +08:00
if ( ! nsjconf - > proc_path . empty ( ) ) {
2018-02-12 06:44:43 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , /* src= */ " " , nsjconf - > proc_path , " proc " ,
/* options= */ " " , nsjconf - > is_proc_rw ? 0 : MS_RDONLY ,
/* is_dir= */ mnt : : NS_DIR_YES , /* is_mandatory= */ true , /* src_env= */ " " ,
/* dst_env= */ " " , /* src_content= */ " " , /* is_symlink= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-04-23 05:54:33 +08:00
}
2015-10-17 22:48:30 +08:00
}
2018-02-10 11:10:18 +08:00
if ( ! ( nsjconf - > chroot . empty ( ) ) ) {
2018-02-12 06:44:43 +08:00
if ( ! mnt : : addMountPtHead ( nsjconf . get ( ) , nsjconf - > chroot , " / " , /* fs_type= */ " " ,
2017-10-17 21:22:23 +08:00
/* options= */ " " ,
nsjconf - > is_root_rw ? ( MS_BIND | MS_REC | MS_PRIVATE )
: ( MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY ) ,
2018-02-12 06:44:43 +08:00
/* is_dir= */ mnt : : NS_DIR_YES , /* is_mandatory= */ true , /* src_env= */ " " ,
/* dst_env= */ " " , /* src_content= */ " " , /* is_symlink= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2015-10-17 22:48:30 +08:00
}
2016-06-19 07:35:06 +08:00
} else {
2018-02-12 06:44:43 +08:00
if ( ! mnt : : addMountPtHead ( nsjconf . get ( ) , /* src= */ " " , " / " , " tmpfs " ,
2018-02-09 22:44:29 +08:00
/* options= */ " " , nsjconf - > is_root_rw ? 0 : MS_RDONLY ,
2018-02-12 06:44:43 +08:00
/* is_dir= */ mnt : : NS_DIR_YES ,
/* is_mandatory= */ true , /* src_env= */ " " , /* dst_env= */ " " ,
/* src_content= */ " " , /* is_symlink= */ false ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2016-06-19 07:35:06 +08:00
}
2015-10-17 22:48:30 +08:00
}
2018-02-10 07:37:23 +08:00
if ( nsjconf - > uids . empty ( ) ) {
2018-02-10 22:50:12 +08:00
idmap_t uid ;
2018-02-10 07:37:23 +08:00
uid . inside_id = getuid ( ) ;
uid . outside_id = getuid ( ) ;
uid . count = 1U ;
uid . is_newidmap = false ;
nsjconf - > uids . push_back ( uid ) ;
2017-02-08 07:36:32 +08:00
}
2018-02-10 07:37:23 +08:00
if ( nsjconf - > gids . empty ( ) ) {
2018-02-10 22:50:12 +08:00
idmap_t gid ;
2018-02-10 07:37:23 +08:00
gid . inside_id = getgid ( ) ;
gid . outside_id = getgid ( ) ;
gid . count = 1U ;
gid . is_newidmap = false ;
nsjconf - > gids . push_back ( gid ) ;
2017-02-08 07:36:32 +08:00
}
2016-10-18 00:17:08 +08:00
2018-02-13 00:31:45 +08:00
for ( int i = optind ; i < argc ; i + + ) {
nsjconf - > argv . push_back ( argv [ i ] ) ;
2017-05-27 08:24:41 +08:00
}
2018-02-12 23:52:05 +08:00
if ( nsjconf - > argv . empty ( ) ) {
2017-05-11 22:17:54 +08:00
cmdlineUsage ( argv [ 0 ] ) ;
2017-09-27 06:47:57 +08:00
LOG_E ( " No command provided " ) ;
2018-02-09 22:44:29 +08:00
return nullptr ;
2015-05-15 05:44:48 +08:00
}
2018-02-12 23:52:05 +08:00
if ( nsjconf - > exec_file . empty ( ) ) {
2017-06-09 07:57:04 +08:00
nsjconf - > exec_file = nsjconf - > argv [ 0 ] ;
}
2015-05-15 05:44:48 +08:00
2017-10-18 23:57:52 +08:00
if ( nsjconf - > use_execveat ) {
# if !defined(__NR_execveat)
2017-10-26 06:26:02 +08:00
LOG_E (
" Your nsjail is compiled without support for the execveat() syscall, yet you "
" specified the --execute_fd flag " ) ;
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-10-18 23:57:52 +08:00
# endif /* !defined(__NR_execveat) */
2018-02-11 23:55:19 +08:00
if ( ( nsjconf - > exec_fd = TEMP_FAILURE_RETRY (
2018-02-12 23:52:05 +08:00
open ( nsjconf - > exec_file . c_str ( ) , O_RDONLY | O_PATH | O_CLOEXEC ) ) ) = = - 1 ) {
PLOG_W ( " Couldn't open '%s' file " , nsjconf - > exec_file . c_str ( ) ) ;
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-10-18 23:57:52 +08:00
}
}
2018-02-09 22:44:29 +08:00
return nsjconf ;
2015-05-15 05:44:48 +08:00
}
2018-02-09 22:44:29 +08:00
} // namespace cmdline