NSJAIL(1)

πŸ“¦ version 3.6, in alpine 3.24, nixos 26.05, nixpkgs unstable

πŸ’… nsjail β€” process isolation tool for linux

okay bestie, listen up: this is the manual page for nsjail, section 1 of the User Commands series. it's a whole jail for your processes. get comfy. 🫢


🌸 NAME

nsjail β€” process isolation tool for linux


✨ SYNOPSIS

nsjail [options] -- path_to_command [args]

πŸ¦‹ DESCRIPTION

So like. NsJail is a process isolation tool for Linux. it literally uses the Linux namespace subsystem, resource limits, and the seccomp-bpf syscall filters of the Linux kernel to lock your little guy up in a sandbox. it's giving maximum security, minimum escape. πŸ”₯


πŸŽ€ Options

okay this is the long part. every single flag is here, i promise. no skipping. πŸ’…
  • --help, -h β€” Help plz.. (that's literally the whole description, bestie, they said what they said πŸ™ˆ)
  • --mode, -M VALUE β€” how should the jail run?? (default: o [MODE_STANDALONE_ONCE]). your choices are:
    • l β€” Wait for connections on a TCP port (specified with --port) [MODE_LISTEN_TCP]
    • o β€” Launch a single process on the console using clone/execve [MODE_STANDALONE_ONCE]
    • e β€” Launch a single process on the console using execve [MODE_STANDALONE_EXECVE]
    • r β€” Launch a single process on the console with clone/execve, keep doing it forever [MODE_STANDALONE_RERUN]
  • --config, -C VALUE β€” Configuration file in the config.proto ProtoBuf format (go peek at the configs/ directory for examples πŸ‘€)
  • --exec_file, -x VALUE β€” File to exec (default: argv[0])
  • --execute_fd β€” Use execveat() to execute a file-descriptor instead of executing the binary path. in that case argv[0]/exec_file denotes a file path before mount namespacing
  • --chroot, -c VALUE β€” Directory containing / of the jail (default: none)
  • --rw β€” Mount chroot dir (/) R/W (default: R/O). careful, you're unlocking the write permission bestie πŸ”“
  • --user, -u VALUE β€” Username/uid of processes inside the jail (default: your current uid). you can also use the inside_ns_uid:outside_ns_uid:count convention here. can be specified multiple times πŸ’–
  • --group, -g VALUE β€” Groupname/gid of processes inside the jail (default: your current gid). you can also use the inside_ns_gid:global_ns_gid:count convention here. can be specified multiple times πŸ’–
  • --hostname, -H VALUE β€” UTS name (hostname) of the jail (default: 'NSJAIL')
  • --cwd, -D VALUE β€” Directory in the namespace the process will run (default: '/')
  • --port, -p VALUE β€” TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)
  • --bindhost VALUE β€” IP address to bind the port to (only in [MODE_LISTEN_TCP]), (default: '::')
  • --max_conns VALUE β€” Maximum number of connections across all IPs (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))
  • --max_conns_per_ip, -i VALUE β€” Maximum number of connections per one IP (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))
  • --log, -l VALUE β€” Log file (default: use log_fd)
  • --log_fd, -L VALUE β€” Log FD (default: 2)
  • --time_limit, -t VALUE β€” Maximum time that a jail can exist, in seconds (default: 600)
  • --max_cpus VALUE β€” Maximum number of CPUs a single jailed process can use (default: 0 'no limit')
  • --daemon, -d β€” Daemonize after start πŸ‘»
  • --verbose, -v β€” Verbose output (it will yap. a lot.)
  • --quiet, -q β€” Log warning and more important messages only
  • --really_quiet, -Q β€” Log fatal messages only. silent treatment mode πŸ’€
  • --keep_env, -e β€” Pass all environment variables be passed process (default: all envars are cleared)
  • --env, -E VALUE β€” 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 ✨
  • --keep_caps β€” Don't drop any capabilities πŸ”₯
  • --cap VALUE β€” Retain this capability, e.g. CAP_PTRACE (can be specified multiple times)
  • --silent β€” Redirect child process' fd:0/1/2 to /dev/null
  • --stderr_to_null β€” Redirect FD=2 (STDERR_FILENO) to /dev/null
  • --skip_setsid β€” Don't call setsid(), allows for terminal signal handling in the sandboxed process. Dangerous ⚠️ like fr, they put it in the manpage for a reason
  • --pass_fd VALUE β€” Don't close this FD before executing the child process (can be specified multiple times), by default: 0/1/2 are kept open
  • --disable_no_new_privs β€” Don't set the prctl(NO_NEW_PRIVS, 1) (DANGEROUS) πŸ™ˆ bestie please
  • --rlimit_as VALUE β€” RLIMIT_AS in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM_INFINITY (default: 4096)
  • --rlimit_core VALUE β€” RLIMIT_CORE in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current limit, 'inf' for RLIM_INFINITY (default: 0)
  • --rlimit_cpu VALUE β€” RLIMIT_CPU, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM_INFINITY (default: 600)
  • --rlimit_fsize VALUE β€” RLIMIT_FSIZE in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM_INFINITY (default: 1)
  • --rlimit_nofile VALUE β€” RLIMIT_NOFILE, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current limit, 'inf' for RLIM_INFINITY (default: 32)
  • --rlimit_nproc VALUE β€” RLIMIT_NPROC, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM_INFINITY (default: 'soft')
  • --rlimit_stack VALUE β€” RLIMIT_STACK in MB, 'max' or 'hard' for the current hard limit, 'def' or 'soft' for the current soft limit, 'inf' for RLIM_INFINITY (default: 'soft')
  • --disable_rlimits β€” Disable all rlimits, default to limits set by parent
  • --persona_addr_compat_layout β€” personality(ADDR_COMPAT_LAYOUT)
  • --persona_mmap_page_zero β€” personality(MMAP_PAGE_ZERO)
  • --persona_read_implies_exec β€” personality(READ_IMPLIES_EXEC)
  • --persona_addr_limit_3gb β€” personality(ADDR_LIMIT_3GB)
  • --persona_addr_no_randomize β€” personality(ADDR_NO_RANDOMIZE)
  • --disable_clone_newnet, -N β€” Don't use CLONE_NEWNET. Enable global networking inside the jail 🌐 (networking girlies stay winning)
  • --disable_clone_newuser β€” Don't use CLONE_NEWUSER. Requires euid==0
  • --disable_clone_newns β€” Don't use CLONE_NEWNS
  • --disable_clone_newpid β€” Don't use CLONE_NEWPID
  • --disable_clone_newipc β€” Don't use CLONE_NEWIPC
  • --disable_clone_newuts β€” Don't use CLONE_NEWUTS
  • --disable_clone_newcgroup β€” Don't use CLONE_NEWCGROUP. Might be required for kernel versions < 4.6 ⭐
  • --uid_mapping, -U VALUE β€” Add a custom uid mapping of the form inside_uid:outside_uid:count. setting this requires newuidmap (set-uid) to be present
  • --gid_mapping, -G VALUE β€” Add a custom gid mapping of the form inside_gid:outside_gid:count. setting this requires newgidmap (set-uid) to be present
  • --bindmount_ro, -R VALUE β€” List of mountpoints to be mounted --bind (ro) inside the container. can be specified multiple times. supports 'source' syntax, or 'source:dest'
  • --bindmount, -B VALUE β€” List of mountpoints to be mounted --bind (rw) inside the container. can be specified multiple times. supports 'source' syntax, or 'source:dest'
  • --tmpfsmount, -T VALUE β€” 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 πŸŽ€
  • --mount, -m VALUE β€” Arbitrary mount, format src:dst:fs_type:options
  • --symlink, -s VALUE β€” Symlink, format src:dst
  • --disable_proc β€” Disable mounting procfs in the jail
  • --proc_path VALUE β€” Path used to mount procfs (default: '/proc')
  • --proc_rw β€” Is procfs mounted as R/W (default: R/O)
  • --seccomp_policy, -P VALUE β€” Path to file containing seccomp-bpf policy (see kafel/)
  • --seccomp_string VALUE β€” String with kafel seccomp-bpf policy (see kafel/)
  • --seccomp_log β€” Use SECCOMP_FILTER_FLAG_LOG. log all actions except SECCOMP_RET_ALLOW. supported since kernel version 4.14 πŸ“
  • --cgroup_mem_max VALUE β€” Maximum number of bytes to use in the group (default: '0' - disabled)
  • --cgroup_mem_memsw_max VALUE β€” Maximum number of memory+Swap bytes to use in the group (default: '0' - disabled)
  • --cgroup_mem_swap_max VALUE β€” Maximum number of swap bytes to use in the group (default: '-1' - disabled)
  • --cgroup_mem_mount VALUE β€” Location of memory cgroup FS (default: '/sys/fs/cgroup/memory')
  • --cgroup_mem_parent VALUE β€” Which pre-existing memory cgroup to use as a parent (default: 'NSJAIL')
  • --cgroup_pids_max VALUE β€” Maximum number of pids in a cgroup (default: '0' - disabled)
  • --cgroup_pids_mount VALUE β€” Location of pids cgroup FS (default: '/sys/fs/cgroup/pids')
  • --cgroup_pids_parent VALUE β€” Which pre-existing pids cgroup to use as a parent (default: 'NSJAIL')
  • --cgroup_net_cls_classid VALUE β€” Class identifier of network packets in the group (default: '0' - disabled)
  • --cgroup_net_cls_mount VALUE β€” Location of net_cls cgroup FS (default: '/sys/fs/cgroup/net_cls')
  • --cgroup_net_cls_parent VALUE β€” Which pre-existing net_cls cgroup to use as a parent (default: 'NSJAIL')
  • --cgroup_cpu_ms_per_sec VALUE β€” Number of milliseconds of CPU time per second that the process group can use (default: '0' - no limit)
  • --cgroup_cpu_mount VALUE β€” Location of cpu cgroup FS (default: '/sys/fs/cgroup/net_cls') πŸ‘€ yes that's what it says, i'm not touching it
  • --cgroup_cpu_parent VALUE β€” Which pre-existing cpu cgroup to use as a parent (default: 'NSJAIL')
  • --cgroupv2_mount VALUE β€” Location of cgroup v2 directory (default: '/sys/fs/cgroup')
  • --use_cgroupv2 β€” Use cgroup v2 ✨
  • --iface_no_lo β€” Don't bring the 'lo' interface up
  • --iface_own VALUE β€” Move this existing network interface into the new NET namespace. can be specified multiple times
  • --macvlan_iface, -I VALUE β€” Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs'
  • --macvlan_vs_ip VALUE β€” IP of the 'vs' interface (e.g. "192.168.0.1")
  • --macvlan_vs_nm VALUE β€” Netmask of the 'vs' interface (e.g. "255.255.255.0")
  • --macvlan_vs_gw VALUE β€” Default GW for the 'vs' interface (e.g. "192.168.0.1")
  • --macvlan_vs_ma VALUE β€” MAC-address of the 'vs' interface (e.g. "ba:ad:ba:be:45:00") πŸ’… iconic

(part 1 of 2 β€” the rest of the flags are in part 2, keep reading bestie πŸ’–)

✨ EXAMPLES ✨

okay bestie, this is the part where it all comes together 🫢 four little snippets, and honestly? they ate. copy these, run these, live your truth.


🌸 wait on a port and hand over a shell

Wait on a port 31337 for connections, and run /bin/sh:

nsjail -Ml --port 31337 --chroot / -- /bin/sh -i

that's the whole vibe: it hangs out on 31337, and when someone connects it spawns /bin/sh for them. lowkey iconic. πŸ’…

πŸ¦‹ re-run a command as a sub-process

Re-run the echo command as a sub-process:

nsjail -Mr --chroot / -- /bin/echo "ABC"

-Mr keeps bringing it back, over and over, as a sub-process. it's giving "again, and again, and again" energy 😭✨

πŸŽ€ run it exactly once, as a sub-process

Run the echo command once only, as a sub-process:

nsjail -Mo --chroot / -- /bin/echo "ABC"

yep β€” the -Mo version does the thing once, as a sub-process, and then it's done. no reruns, no drama. periodt. πŸ”₯

⭐ no supervisor at all, just send it

Execute the echo command directly, without a supervising process:

nsjail -Me --chroot / --disable_proc -- /bin/echo "ABC"

-Me means it runs the command directly β€” no supervising process hovering over it. and bestie, notice the --disable_proc in there? that's just how this example rolls. main character energy fr fr πŸ‘‘

πŸ’– ngl these four are your whole starter pack β€” port mode, re-run mode, once mode, and direct mode. pick your fighter, keep the flags exactly as written, and you're golden ✨

and that's the whole page, bestie β€” you made it 🌈 this is nsjail, page NSJAIL(1), dated August 2017 β€” go forth, sandbox responsibly, and remember: the vibe changes, the flags never do πŸ’œπŸŽ€

mwah πŸ’‹ β€” see you in the next manpage, iykyk

πŸ“¦ where this page comes from