mrrl-containers

MRRL version of container scripts
git clone https://ccx.te2000.cz/git/mrrl-containers
Log | Files | Refs

commit 5e2bb0736ec2070949c4173dd12c59e47f9042bd
parent c89fdace29ababe01bf19e336bf695041c85411e
Author: Jan Pobrislo <ccx@webprojekty.cz>
Date:   Fri, 18 Dec 2020 05:07:00 +0100

Rewrite the scripts for entering namespace/container in pure execline and AWK, list it's parameters and function.
Diffstat:
Msbin/ns_run | 134++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Asbin/ns_umount_script.awk | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 187 insertions(+), 5 deletions(-)

diff --git a/sbin/ns_run b/sbin/ns_run @@ -1,14 +1,138 @@ -#!/command/execlineb -S0 +#!/command/execlineb -s1 + +## usage: ns_run <root_directory> <executable> [<arg1> ...] +## +## 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 make 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. + +# import variables from environment, with defaults +multisubstitute { + importas -D mnt/ns NS_TMPFS + importas -D /mnt/volumes/containers/bin NS_BIN + importas -D /mnt/chroot NS_ROOT +} + +# check we are PID1 (in a new PID namespace) getpid PID ifelse { importas -i PID PID test 1 -ne $PID } { fdmove -c 1 2 echo "ns_run: fatal: not PID 1" - exit 2 + exit 111 } unexport PID + unshare -m -u -i # new mount, UTS and IPC namespaces foreground { importas -i HOST HOST hostname $HOST } -fdmove -c 3 0 # store original stdin as we are calling pipelined script -pipeline -d { /root/ns_execline.zsh $@ } -execlineb /dev/stdin + +# We will generate final script we exec into 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 + 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-mount -nwt mqueue -o nosuid,nodev,noexec,relatime 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 +} + +if { + if -t { s6-test -V NS_FSTAB } + importas -i NS_FSTAB NS_FSTAB + mount -a --fstab $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 NS_FINAL_SCRIPT NS_FINAL_SCRIPT +execlineb -c $NS_FINAL_SCRIPT diff --git a/sbin/ns_umount_script.awk b/sbin/ns_umount_script.awk @@ -0,0 +1,58 @@ +#!/usr/bin/awk -f +function el_quote(s) { + RESULT="\"${${${1}//\\/\\\\}//\"/\\\"}\"" + gsub(/\\/, "\\\\", s); # first double all backslashes + gsub(/"/, "\\\"", s); # then escape quote marks + return "\"" s "\"" # then surround with quote marks +} + +BEGIN { + # check if necessary variables were defined + if(BIN == "") { exit 100 } + if(ROOT == "") { exit 100 } + + # quote common stings + IF = el_quote(BIN "/if") + UMOUNT = el_quote(BIN "/busybox") " umount" + + # mount IDs seem to be unsigned, so let's use -1 to signify not found + max_id = -1 + root_id = -1 +} + +# read in /proc/self/mountinfo +$5 == "/" { root_id = $1 } +{ + max_id = max_id < $1 ? $1 : max_id + parents[$1] = $2 + mountpoints[$1] = $5 +} + +function _if(opts, s) { + return IF opts " { " s " } " +} + +function umount(opts, s) { + return UMOUNT opts " " el_quote(ROOT s) +} + +function print_umount(mtp){ + print _if("", \ + _if(" -n -t", umount("", mtp)) \ + umount(" -l", mtp) \ + ) +} + +function recursively_umount(mount_id, id) { + for(id=max_id; id>=0; id--){ + if(parents[id] == mount_id){ + recursively_umount(id) + } + } + print_umount(mountpoints[mount_id]) +} + +END{ + if(root_id == -1) { exit 111 } + recursively_umount(root_id) +}