#!/command/execlineb -s1 ## usage: ns_run [ ...] ## ## Creates isolated namespace/container with given root and runs given ## executable in it. ## ## Environment variables used: ## HOST - hostname to set ## NS_ROOT - where to bind-mount the root directory ## NS_EXTRA - extra execline script to run after setting up the namespaces ## and mounting essential filesystems but before entering it ## and unmounting host filesystem ## NS_FSTAB - file with extra mounts to perform after running above script ## NS_TMPFS - place to store binaries in the container that are run ## before dropping privs, relative path from new root ## NS_BIN - directory to get said binaries from; currently needs: ## - `if` from execline ## - busybox with `umount` and `chpst` functions ## - anything you wish to call before and for dropping privs, ## eg. s6-applyuidgid ## All statically linked of course. ## NS_NO_PID1 - Allow not running as init process of the namespace. # import variables from environment, with defaults multisubstitute { importas -D container HOST HOST importas -D /mnt/chroot NS_ROOT NS_ROOT importas -D mnt/ns NS_TMPFS NS_TMPFS importas -D /mnt/volumes/containers/bin NS_BIN NS_BIN } # check we are PID1 (in a new PID namespace) getpid PID ifelse { importas -D "" NS_NO_PID1 NS_NO_PID1 importas -i PID PID test -z ${NS_NO_PID1} -a 1 -ne $PID } { fdmove -c 1 2 foreground { echo "ns_run: fatal: not PID 1" } exit 111 } unexport PID unshare -m -u -i # new mount, UTS and IPC namespaces foreground { importas -i HOST HOST hostname $HOST } # We will generate final script we will exec into to enter the container. # We need to generate it before we start mounting anything, # so only the mountpoints that exist at this point will get unmounted and # everything we will mount below will stay. backtick -i NS_FINAL_SCRIPT { # Generate execline script that performs pivot_root # and umounts all the filesystems not used by the container # formerly: /root/ns_execline.zsh $@ if { printf "%s\n" "if { pivot_root . \${NS_TMPFS}/oldroot }" } if { ns_umount_script.awk -vROOT=/${NS_TMPFS}/oldroot -vBIN=/${NS_TMPFS}/bin /proc/self/mountinfo } if { printf "%s\n" "./${NS_TMPFS}/bin/busybox chpst -/ ." } # quote all the arguments we got for interpretation by execline forx -o 0 X { $@ } importas -i X X s6-quote -- $X } # mount and enter the chroot directory if { mount --rbind $1 $NS_ROOT } cd $NS_ROOT ## this will be better handled by NS_EXTRA script ## and perhaps /etc/resolv.conf -> /run/resolv.conf symlink # foreground { cp /etc/resolv.conf etc/ } # /proc if { mount -t proc proc proc } # /dev if { s6-mount -nwt tmpfs -o nosuid,dev,mode=0755 dev dev } if { mknod -m 666 dev/null c 1 3 } if { mknod -m 666 dev/full c 1 7 } if { mknod -m 666 dev/ptmx c 5 2 } if { mknod -m 644 dev/random c 1 8 } if { mknod -m 644 dev/urandom c 1 9 } if { mknod -m 666 dev/zero c 1 5 } if { mknod -m 666 dev/tty c 5 0 } # shm, pts and mqueue are provided below # also have some convenience dirs in place for optionally bind-mounting them if { mkdir # dev/shm run/shm dev/pts dev/mqueue dev/block dev/bus dev/char dev/dri dev/input dev/loop dev/net dev/snd dev/usb } if { mount -t devpts devpts dev/pts } #if { s6-mount -nwt tmpfs -o nosuid,nodev,mode=1777 shm dev/shm } if { s6-ln -sf ../run/shm dev/shm } if { chmod 1777 run/shm } if { s6-mount -nwt mqueue -o nosuid,nodev,noexec mqueue dev/mqueue } # leave /dev read-write for now, so stuff can be added by scripts below # mountpoint for privileged operations and pivot_root if { s6-mount -nwt tmpfs -o nosuid,nodev,mode=700 mnt_ns $NS_TMPFS } if { mkdir ${NS_TMPFS}/oldroot ${NS_TMPFS}/bin } #if { s6-hiercopy $NS_BIN ${NS_TMPFS}/bin } if { s6-mount -n -o bind,ro $NS_BIN ${NS_TMPFS}/bin } # container-specific setup provided in environment if { if -t { s6-test -v NS_EXTRA } importas -i NS_EXTRA NS_EXTRA execlineb -c $NS_EXTRA } unexport NS_EXTRA if { if -t { s6-test -v NS_FSTAB } importas -i NS_FSTAB NS_FSTAB mount -a --fstab $NS_FSTAB } unexport NS_FSTAB # now we can make /dev immutable if { mount -o remount,ro dev } # exec into the script we generated above, it: # * does pivot_root to change rootdir # * umounts all undesired filesystems # * execs into $@ importas -i -u NS_FINAL_SCRIPT NS_FINAL_SCRIPT execlineb -c $NS_FINAL_SCRIPT