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) " } ,
2020-07-07 20:07:22 +08:00
{ { " user " , required_argument , NULL , ' u ' } , " Username/uid of processes 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 processes 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 " } ,
2017-09-14 04:03:21 +08:00
{ { " 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: '::') " } ,
2021-02-10 06:13:35 +08:00
{ { " max_conns " , required_argument , NULL , 0x608 } , " Maximum number of connections across all IPs (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited)) " } ,
2017-09-14 04:03:21 +08:00
{ { " 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 " } ,
2019-08-29 04:18:58 +08:00
{ { " keep_env " , no_argument , NULL , ' e ' } , " Pass all environment variables to the child process (default: all envars are cleared) " } ,
{ { " env " , required_argument , NULL , ' E ' } , " Additional environment variable (can be used multiple times). If the envar doesn't contain '=' (e.g. just the 'DISPLAY' string), the current envar value will be used " } ,
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 " } ,
2018-06-25 10:10:42 +08:00
{ { " stderr_to_null " , no_argument , NULL , 0x0503 } , " Redirect child process' fd:2 (STDERR_FILENO) 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') " } ,
2019-08-05 18:25:22 +08:00
{ { " disable_rlimits " , no_argument , NULL , 0x0208 } , " Disable all rlimits, default to limits set by parent " } ,
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 " } ,
2021-05-11 20:48:45 +08:00
{ { " enable_clone_newtime " , no_argument , NULL , 0x0408 } , " Use CLONE_NEWTIME. Supported with kernel versions >= 5.3 " } ,
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' " } ,
2018-06-12 21:37:30 +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. Alternatively, use '-m none:dest:tmpfs:size=8388608' " } ,
2018-02-11 22:07:24 +08:00
{ { " mount " , required_argument , NULL , ' m ' } , " Arbitrary mount, format src:dst:fs_type:options " } ,
2018-06-12 21:37:30 +08:00
{ { " symlink " , required_argument , NULL , ' s ' } , " Symlink, format src:dst " } ,
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/) " } ,
2018-05-24 21:21:42 +08:00
{ { " seccomp_log " , no_argument , NULL , 0x0902 } , " Use SECCOMP_FILTER_FLAG_LOG. Log all actions except SECCOMP_RET_ALLOW). Supported since kernel version 4.14 " } ,
2019-07-01 03:50:56 +08:00
{ { " nice_level " , required_argument , NULL , 0x0903 } , " Set jailed process niceness (-20 is highest -priority, 19 is lowest). By default, set to 19 " } ,
2017-09-14 04:03:21 +08:00
{ { " 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-12-05 21:35:16 +08:00
{ { " cgroup_cpu_ms_per_sec " , required_argument , NULL , 0x0831 } , " Number of milliseconds of CPU time per second that the process group can use (default: '0' - no limit) " } ,
2021-04-03 23:31:56 +08:00
{ { " cgroup_cpu_mount " , required_argument , NULL , 0x0832 } , " Location of cpu cgroup FS (default: '/sys/fs/cgroup/cpu') " } ,
2018-02-04 11:15:19 +08:00
{ { " cgroup_cpu_parent " , required_argument , NULL , 0x0833 } , " Which pre-existing cpu cgroup to use as a parent (default: 'NSJAIL') " } ,
2019-07-26 22:02:17 +08:00
{ { " cgroupv2_mount " , required_argument , NULL , 0x0834 } , " Location of cgroupv2 directory (default: '/sys/fs/cgroup') " } ,
{ { " use_cgroupv2 " , no_argument , NULL , 0x0835 } , " Use cgroup v2 " } ,
2017-09-30 04:18:16 +08:00
{ { " iface_no_lo " , no_argument , NULL , 0x700 } , " Don't bring the 'lo' interface up " } ,
2018-05-31 20:45:44 +08:00
{ { " iface_own " , required_argument , NULL , 0x704 } , " Move this existing network interface into the new NET namespace. Can be specified multiple times " } ,
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 \" ) " } ,
2018-10-24 04:24:43 +08:00
{ { " macvlan_vs_ma " , required_argument , NULL , 0x705 } , " MAC-address of the 'vs' interface (e.g. \" ba:ad:ba:be:45:00 \" ) " } ,
2021-06-16 21:59:12 +08:00
{ { " macvlan_vs_mo " , required_argument , NULL , 0x706 } , " Mode of the 'vs' interface. Can be either 'private', 'vepa', 'bridge' or 'passthru' (default: 'private') " } ,
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: " ) ;
2018-02-13 23:53:45 +08:00
for ( size_t i = 0 ; i < ARR_SZ ( custom_opts ) ; i + + ) {
2017-05-11 22:17:54 +08:00
cmdlineOptUsage ( & custom_opts [ i ] ) ;
}
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-10-29 00:15:55 +08:00
void addEnv ( nsjconf_t * nsjconf , const std : : string & env ) {
if ( env . find ( ' = ' ) ! = std : : string : : npos ) {
nsjconf - > envs . push_back ( env ) ;
return ;
}
char * e = getenv ( env . c_str ( ) ) ;
if ( ! e ) {
2019-08-29 04:18:58 +08:00
LOG_W ( " Requested to use the '%s' envar, but it's not set. It'll be ignored " ,
2018-10-29 04:03:10 +08:00
env . c_str ( ) ) ;
2018-10-29 00:15:55 +08:00
return ;
}
nsjconf - > envs . push_back ( std : : string ( env ) . append ( " = " ) . append ( e ) ) ;
}
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 (
2018-02-18 09:47:46 +08:00
" Jail parameters: hostname:'%s', chroot:'%s', process:'%s', bind:[%s]:%d, "
2021-02-10 06:13:35 +08:00
" max_conns:%u, max_conns_per_ip:%u, time_limit:% " PRId64
2018-06-01 23:15:47 +08:00
" , personality:%#lx, daemonize:%s, clone_newnet:%s, "
2018-11-22 15:44:25 +08:00
" clone_newuser:%s, clone_newns:%s, clone_newpid:%s, clone_newipc:%s, clone_newuts:%s, "
2021-05-18 20:38:01 +08:00
" clone_newcgroup:%s, clone_newtime:%s, keep_caps:%s, disable_no_new_privs:%s, "
" max_cpus:%zu " ,
2018-02-18 09:47:46 +08:00
nsjconf - > hostname . c_str ( ) , nsjconf - > chroot . c_str ( ) ,
nsjconf - > exec_file . empty ( ) ? nsjconf - > argv [ 0 ] . c_str ( ) : nsjconf - > exec_file . c_str ( ) ,
2021-02-10 06:13:35 +08:00
nsjconf - > bindhost . c_str ( ) , nsjconf - > port , nsjconf - > max_conns , nsjconf - > max_conns_per_ip ,
nsjconf - > tlimit , nsjconf - > personality , logYesNo ( nsjconf - > daemonize ) ,
logYesNo ( nsjconf - > clone_newnet ) , logYesNo ( nsjconf - > clone_newuser ) ,
logYesNo ( nsjconf - > clone_newns ) , logYesNo ( nsjconf - > clone_newpid ) ,
logYesNo ( nsjconf - > clone_newipc ) , logYesNo ( nsjconf - > clone_newuts ) ,
2021-05-18 20:38:01 +08:00
logYesNo ( nsjconf - > clone_newcgroup ) , logYesNo ( nsjconf - > clone_newtime ) ,
logYesNo ( nsjconf - > keep_caps ) , 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 ) {
2019-01-21 01:43:42 +08:00
LOG_I (
" %s: %s " , p . is_symlink ? " Symlink " : " Mount " , 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 (
2018-12-17 15:46:31 +08:00
" 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 (
2018-12-17 15:46:31 +08:00
" 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
}
2018-05-26 05:53:11 +08:00
errno = 0 ;
2018-05-26 06:40:28 +08:00
uint64_t val = strtoull ( optarg , NULL , 0 ) ;
2015-10-14 01:06:49 +08:00
if ( val = = ULLONG_MAX & & errno ! = 0 ) {
2018-05-26 19:54:17 +08:00
PLOG_F ( " strtoull('%s', 0) " , optarg ) ;
2015-05-15 05:44:48 +08:00
}
2018-05-26 06:40:28 +08:00
return val * mul ;
2015-05-15 05:44:48 +08:00
}
2018-02-20 21:16:28 +08:00
static std : : string argFromVec ( const std : : vector < std : : string > & vec , size_t pos ) {
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-17 10:14:54 +08:00
static bool setupArgv ( nsjconf_t * nsjconf , int argc , char * * argv , int optind ) {
2019-03-30 23:10:14 +08:00
/*
* If user provided cmdline via nsjail [ opts ] - - [ cmdline ] , then override the one from the
* config file
*/
if ( optind < argc ) {
nsjconf - > argv . clear ( ) ;
for ( int i = optind ; i < argc ; i + + ) {
nsjconf - > argv . push_back ( argv [ i ] ) ;
}
2018-02-17 10:14:54 +08:00
}
2019-04-02 04:42:14 +08:00
if ( nsjconf - > exec_file . empty ( ) & & nsjconf - > argv . size ( ) > 0 ) {
2018-02-17 10:14:54 +08:00
nsjconf - > exec_file = nsjconf - > argv [ 0 ] ;
}
2019-03-30 23:10:14 +08:00
if ( nsjconf - > exec_file . empty ( ) ) {
cmdlineUsage ( argv [ 0 ] ) ;
LOG_E ( " No command-line provided " ) ;
return false ;
}
2018-02-17 10:14:54 +08:00
if ( nsjconf - > use_execveat ) {
# if !defined(__NR_execveat)
LOG_E (
" Your nsjail is compiled without support for the execveat() syscall, yet you "
" specified the --execute_fd flag " ) ;
return false ;
# endif /* !defined(__NR_execveat) */
if ( ( nsjconf - > exec_fd = TEMP_FAILURE_RETRY (
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 ( ) ) ;
return false ;
}
}
return true ;
}
2018-06-12 21:37:30 +08:00
static bool setupMounts ( nsjconf_t * nsjconf ) {
2018-02-17 10:14:54 +08:00
if ( ! ( nsjconf - > chroot . empty ( ) ) ) {
2018-05-30 21:03:01 +08:00
if ( ! mnt : : addMountPtHead ( nsjconf , nsjconf - > chroot , " / " , /* fstype= */ " " ,
2018-02-17 10:14:54 +08:00
/* options= */ " " ,
nsjconf - > is_root_rw ? ( MS_BIND | MS_REC | MS_PRIVATE )
: ( MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY ) ,
/* is_dir= */ mnt : : NS_DIR_YES , /* is_mandatory= */ true , /* src_env= */ " " ,
/* dst_env= */ " " , /* src_content= */ " " , /* is_symlink= */ false ) ) {
return false ;
}
} else {
if ( ! mnt : : addMountPtHead ( nsjconf , /* src= */ " " , " / " , " tmpfs " ,
/* options= */ " " , nsjconf - > is_root_rw ? 0 : MS_RDONLY ,
/* is_dir= */ mnt : : NS_DIR_YES ,
/* is_mandatory= */ true , /* src_env= */ " " , /* dst_env= */ " " ,
/* src_content= */ " " , /* is_symlink= */ false ) ) {
return false ;
}
}
if ( ! nsjconf - > proc_path . empty ( ) ) {
if ( ! mnt : : addMountPtTail ( nsjconf , /* 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 ) ) {
return false ;
}
}
2018-02-21 04:03:22 +08:00
return true ;
}
void setupUsers ( nsjconf_t * nsjconf ) {
2018-02-17 10:14:54 +08:00
if ( nsjconf - > uids . empty ( ) ) {
idmap_t uid ;
uid . inside_id = getuid ( ) ;
uid . outside_id = getuid ( ) ;
uid . count = 1U ;
uid . is_newidmap = false ;
nsjconf - > uids . push_back ( uid ) ;
}
if ( nsjconf - > gids . empty ( ) ) {
idmap_t gid ;
gid . inside_id = getgid ( ) ;
gid . outside_id = getgid ( ) ;
gid . count = 1U ;
gid . is_newidmap = false ;
nsjconf - > gids . push_back ( gid ) ;
}
}
2021-06-16 21:59:12 +08:00
std : : string parseMACVlanMode ( const char * optarg ) {
2021-06-16 23:44:07 +08:00
if ( strcasecmp ( optarg , " private " ) ! = 0 & & strcasecmp ( optarg , " vepa " ) ! = 0 & &
strcasecmp ( optarg , " bridge " ) ! = 0 & & strcasecmp ( optarg , " passthru " ) ! = 0 ) {
2021-06-16 21:59:12 +08:00
LOG_F (
2021-06-16 23:44:07 +08:00
" macvlan mode can only be one of the values: "
" 'private'/'vepa'/'bridge'/'passthru' ('%s' "
2021-06-16 21:59:12 +08:00
" provided). " ,
optarg ) ;
2021-06-16 23:44:07 +08:00
}
2021-06-16 21:59:12 +08:00
return std : : string ( optarg ) ;
}
2018-02-10 22:50:12 +08:00
std : : unique_ptr < nsjconf_t > parseArgs ( int argc , char * argv [ ] ) {
2018-02-16 23:05:26 +08:00
std : : unique_ptr < nsjconf_t > nsjconf ( new 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 = " :: " ;
nsjconf - > daemonize = false ;
nsjconf - > tlimit = 0 ;
nsjconf - > max_cpus = 0 ;
2018-06-12 22:57:19 +08:00
nsjconf - > keep_env = false ;
2018-02-09 22:44:29 +08:00
nsjconf - > keep_caps = false ;
nsjconf - > disable_no_new_privs = false ;
2019-02-07 00:06:42 +08:00
nsjconf - > rl_as = 4096ULL * ( 1024ULL * 1024ULL ) ;
nsjconf - > rl_core = 0ULL ;
nsjconf - > rl_cpu = 600ULL ;
nsjconf - > rl_fsize = 1ULL * ( 1024ULL * 1024ULL ) ;
nsjconf - > rl_nofile = 32ULL ;
2018-02-09 22:44:29 +08:00
nsjconf - > rl_nproc = parseRLimit ( RLIMIT_NPROC , " soft " , 1 ) ;
nsjconf - > rl_stack = parseRLimit ( RLIMIT_STACK , " soft " , 1 ) ;
2019-08-05 18:25:22 +08:00
nsjconf - > disable_rl = false ;
2018-02-09 22:44:29 +08:00
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 ;
2021-05-11 20:48:45 +08:00
nsjconf - > clone_newcgroup = false ;
2018-02-09 22:44:29 +08:00
nsjconf - > mode = MODE_STANDALONE_ONCE ;
nsjconf - > is_root_rw = false ;
nsjconf - > is_silent = false ;
2018-06-25 09:12:27 +08:00
nsjconf - > stderr_to_null = false ;
2018-06-25 10:10:42 +08:00
nsjconf - > skip_setsid = false ;
2021-02-10 06:13:35 +08:00
nsjconf - > max_conns = 0 ;
2018-02-09 22:44:29 +08:00
nsjconf - > max_conns_per_ip = 0 ;
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 ;
2019-07-26 22:02:17 +08:00
nsjconf - > cgroupv2_mount = " /sys/fs/cgroup " ;
nsjconf - > use_cgroupv2 = false ;
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 " ;
2018-10-23 21:05:50 +08:00
nsjconf - > iface_vs_ma = " " ;
2021-06-16 21:59:12 +08:00
nsjconf - > iface_vs_mo = " private " ;
2018-02-09 22:44:29 +08:00
nsjconf - > orig_uid = getuid ( ) ;
2019-03-30 04:38:14 +08:00
nsjconf - > orig_euid = geteuid ( ) ;
2018-02-09 22:44:29 +08:00
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 ;
2018-05-23 21:38:45 +08:00
nsjconf - > seccomp_log = false ;
2019-07-01 03:50:56 +08:00
nsjconf - > nice_level = 19 ;
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 ) ;
2017-05-11 22:17:54 +08:00
// Generate options array for getopt_long.
2018-06-01 23:15:47 +08:00
size_t options_length = ARR_SZ ( custom_opts ) + 1 ;
2017-05-11 22:17:54 +08:00
struct option opts [ options_length ] ;
2018-02-13 23:53:45 +08:00
for ( unsigned i = 0 ; i < ARR_SZ ( custom_opts ) ; i + + ) {
2015-05-15 05:44:48 +08:00
opts [ i ] = custom_opts [ i ] . opt ;
}
2017-05-11 22:17:54 +08:00
// 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-06-12 21:37:30 +08:00
" x:H:D:C:c:p:i:u:g:l:L:t:M:NdvqQeh?E:R:B:T:m:s: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 ' :
2019-08-19 17:34:34 +08:00
if ( ! util : : isANumber ( optarg ) ) {
LOG_E ( " Couldn't parse TCP port '%s' " , optarg ) ;
return nullptr ;
}
2018-05-26 19:54:17 +08:00
nsjconf - > port = strtoumax ( 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 ;
2021-02-10 06:13:35 +08:00
case 0x608 :
nsjconf - > max_conns = strtoul ( optarg , NULL , 0 ) ;
break ;
2015-05-15 05:44:48 +08:00
case ' i ' :
nsjconf - > max_conns_per_ip = strtoul ( optarg , NULL , 0 ) ;
break ;
case ' l ' :
2019-10-03 01:43:58 +08:00
logs : : logFile ( optarg , STDERR_FILENO ) ;
2015-05-15 05:44:48 +08:00
break ;
2017-06-12 06:06:13 +08:00
case ' L ' :
2019-10-03 01:43:58 +08:00
logs : : logFile ( " " , std : : strtol ( optarg , NULL , 0 ) ) ;
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-06-07 22:51:50 +08:00
logs : : logLevel ( logs : : DEBUG ) ;
2017-02-15 04:54:02 +08:00
break ;
case ' q ' :
2018-06-07 22:51:50 +08:00
logs : : logLevel ( logs : : WARNING ) ;
2015-05-15 05:44:48 +08:00
break ;
2017-10-07 08:03:51 +08:00
case ' Q ' :
2018-06-07 22:51:50 +08:00
logs : : logLevel ( logs : : FATAL ) ;
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 ' :
2018-05-26 19:54:17 +08:00
nsjconf - > tlimit = ( uint64_t ) strtoull ( optarg , NULL , 0 ) ;
2015-05-15 05:44:48 +08:00
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 ;
2019-08-05 18:25:22 +08:00
case 0x0208 :
nsjconf - > disable_rl = true ;
break ;
2015-05-15 05:44:48 +08:00
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 :
2021-05-11 20:48:45 +08:00
nsjconf - > clone_newtime = true ;
2016-06-19 17:55:55 +08:00
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 ;
2018-06-25 10:10:42 +08:00
case 0x0503 :
nsjconf - > stderr_to_null = true ;
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 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 ' :
2018-10-29 00:15:55 +08:00
addEnv ( nsjconf . get ( ) , optarg ) ;
2018-02-10 06:04:57 +08:00
break ;
2017-10-09 05:00:45 +08:00
case ' u ' : {
2018-02-20 21:16:28 +08:00
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string i_id = argFromVec ( subopts , 0 ) ;
std : : string o_id = argFromVec ( subopts , 1 ) ;
std : : string cnt = argFromVec ( subopts , 2 ) ;
2018-02-16 22:23:02 +08:00
size_t count = strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
2018-02-11 21:56:30 +08:00
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-20 21:16:28 +08:00
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string i_id = argFromVec ( subopts , 0 ) ;
std : : string o_id = argFromVec ( subopts , 1 ) ;
std : : string cnt = argFromVec ( subopts , 2 ) ;
2018-02-16 22:23:02 +08:00
size_t count = strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
2018-02-11 21:56:30 +08:00
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-20 21:16:28 +08:00
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string i_id = argFromVec ( subopts , 0 ) ;
std : : string o_id = argFromVec ( subopts , 1 ) ;
std : : string cnt = argFromVec ( subopts , 2 ) ;
2018-02-16 22:23:02 +08:00
size_t count = strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
2018-02-11 21:56:30 +08:00
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-20 21:16:28 +08:00
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string i_id = argFromVec ( subopts , 0 ) ;
std : : string o_id = argFromVec ( subopts , 1 ) ;
std : : string cnt = argFromVec ( subopts , 2 ) ;
2018-02-16 22:23:02 +08:00
size_t count = strtoul ( cnt . c_str ( ) , nullptr , 0 ) ;
2018-02-11 21:56:30 +08:00
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-20 21:16:28 +08:00
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string src = argFromVec ( subopts , 0 ) ;
std : : string dst = argFromVec ( subopts , 1 ) ;
2018-02-11 21:56:30 +08:00
if ( dst . empty ( ) ) {
dst = src ;
}
2018-05-30 21:03:01 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , src , dst , /* fstype= */ " " ,
2018-02-12 06:44:43 +08:00
/* 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-20 21:16:28 +08:00
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string src = argFromVec ( subopts , 0 ) ;
std : : string dst = argFromVec ( subopts , 1 ) ;
2018-02-11 21:56:30 +08:00
if ( dst . empty ( ) ) {
dst = src ;
}
2018-05-30 21:03:01 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , src , dst , /* fstype= */ " " ,
2018-02-12 06:44:43 +08:00
/* 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 ;
2018-06-12 21:37:30 +08:00
case ' T ' : {
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , " " , optarg , /* fstype= */ " tmpfs " ,
/* options= */ " size=4194304 " , 0 ,
/* is_dir= */ mnt : : NS_DIR_YES , /* is_mandatory= */ true ,
/* src_env= */ " " , /* dst_env= */ " " , /* src_content= */ " " ,
/* is_symlink= */ false ) ) {
return nullptr ;
}
} ; break ;
2018-02-11 22:07:24 +08:00
case ' m ' : {
2018-02-20 21:16:28 +08:00
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string src = argFromVec ( subopts , 0 ) ;
std : : string dst = argFromVec ( subopts , 1 ) ;
2018-02-11 22:07:24 +08:00
if ( dst . empty ( ) ) {
dst = src ;
}
2018-02-20 21:16:28 +08:00
std : : string fs_type = argFromVec ( subopts , 2 ) ;
std : : string options = argFromVec ( subopts , 3 ) ;
2018-05-30 21:03:01 +08:00
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , src , dst , /* fstype= */ fs_type ,
2018-02-12 06:44:43 +08:00
/* 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 ;
2018-06-12 21:37:30 +08:00
case ' s ' : {
std : : vector < std : : string > subopts = util : : strSplit ( optarg , ' : ' ) ;
std : : string src = argFromVec ( subopts , 0 ) ;
std : : string dst = argFromVec ( subopts , 1 ) ;
if ( ! mnt : : addMountPtTail ( nsjconf . get ( ) , src , dst , /* fstype= */ " " ,
/* options= */ " " , /* flags= */ 0 ,
/* is_dir= */ mnt : : NS_DIR_NO , /* is_mandatory= */ true ,
/* src_env= */ " " , /* dst_env= */ " " , /* src_content= */ " " ,
/* is_symlink= */ true ) ) {
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 ;
2018-05-30 21:26:09 +08:00
case 0x704 :
nsjconf - > ifaces . push_back ( optarg ) ;
break ;
2018-10-23 21:05:50 +08:00
case 0x705 :
nsjconf - > iface_vs_ma = optarg ;
break ;
2021-06-16 21:59:12 +08:00
case 0x706 :
nsjconf - > iface_vs_mo = parseMACVlanMode ( optarg ) ;
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 ;
2019-07-26 22:02:17 +08:00
case 0x834 :
nsjconf - > cgroupv2_mount = optarg ;
break ;
case 0x835 :
nsjconf - > use_cgroupv2 = true ;
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 ;
2018-05-23 21:32:45 +08:00
case 0x902 :
nsjconf - > seccomp_log = true ;
break ;
2019-07-01 03:50:56 +08:00
case 0x903 :
nsjconf - > nice_level = ( int ) strtol ( optarg , NULL , 0 ) ;
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-06-07 22:51:50 +08:00
if ( nsjconf - > daemonize & & ! logs : : logSet ( ) ) {
2019-10-03 01:43:58 +08:00
logs : : logFile ( _LOG_DEFAULT_FILE , STDERR_FILENO ) ;
2018-02-11 00:49:15 +08:00
}
2018-06-12 21:37:30 +08:00
if ( ! setupMounts ( nsjconf . get ( ) ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2015-05-15 05:44:48 +08:00
}
2018-02-17 10:14:54 +08:00
if ( ! setupArgv ( nsjconf . get ( ) , argc , argv , optind ) ) {
2018-02-09 22:44:29 +08:00
return nullptr ;
2017-10-18 23:57:52 +08:00
}
2018-02-21 04:03:22 +08:00
setupUsers ( nsjconf . get ( ) ) ;
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