From fc6ee67cf23c2b8212c802777b339395260f3bee Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 14:46:11 -0500 Subject: [PATCH 1/9] app_containers: Optionally support user namespaces using the env variable CONTAINER_USE_USERNS --- app_containers/.local/bin/run_app_container | 29 +++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index 9bd1a27..003021a 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -5,6 +5,14 @@ die() { exit 1 } +exit() { + rm -rf "$container_xdg_runtime" + if [ "$CONTAINER_USE_USERNS" = true ]; then + setfacl -x u:$((private_users + 1000)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY + xhost -si:localuser:\#$((private_users + 1000)) + fi +} + [ -z "$CONTAINER_NAME" ] && die "\$CONTAINER_NAME not set" [ -z "$DISPLAY" ] && die "\$DISPLAY not set (you must run the script in a desktop environment" @@ -15,8 +23,8 @@ if [ -f "$config" ]; then fi # Create a XDG_RUNTIME_DIR for guest on host -container_xdg_runtime="$(mktemp -d)" -trap 'rm -rf -- "$container_xdg_runtime"' EXIT +container_xdg_runtime="$(mktemp -d -p /var/tmp)" +trap exit EXIT # Link the current wayland session to the container's xdg runtime # Note that the session itself must be bind-mounted first @@ -45,9 +53,20 @@ if [ "$CONTAINER_RUN_AS_ROOT" = true ]; then homedir=/root fi +# Userns-related config +# Default to identity mapping, which does not provide uid isolation but does for capabilities +private_users=identity +bind_opts="" +if [ "$CONTAINER_USE_USERNS" = true ]; then + private_users=$(shuf -i 65536-$((2147483647 - 65536)) -n1) # Pick a random starting offset + bind_opts="idmap" # Note: custom mounts specified by the user are expected to incldue the idmap option as well + # Grant the user inside the namespace access to the Wayland / Xorg display + setfacl -m u:$((private_users + 1000)):rwx $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY + xhost +si:localuser:\#$((private_users + 1000)) +fi + SUDO_ASKPASS=$HOME/.local/bin/askpass-bemenu sudo -A systemd-nspawn -M $CONTAINER_NAME \ - `# This doesn't provide userns isolation, but it does provide capability isolation` \ - --private-users=identity \ + --private-users=$private_users --private-users-ownership=map \ `# DNS (when containers do not have their own netns)` \ --bind-ro=/run/systemd/resolve/stub-resolv.conf:/etc/resolv.conf \ `# GPU` \ @@ -57,7 +76,7 @@ SUDO_ASKPASS=$HOME/.local/bin/askpass-bemenu sudo -A systemd-nspawn -M $CONTAINE --bind-ro=/dev/input \ --property=DeviceAllow='char-input r' \ `# Xdg runtime` \ - --bind=$container_xdg_runtime:/run/xdg \ + --bind=$container_xdg_runtime:/run/xdg:$bind_opts \ --setenv=XDG_RUNTIME_DIR=/run/xdg \ `# Xorg / Xwayland` \ --bind=/tmp/.X11-unix \ From fab54bfafa92708e3df5d8fba127281ec7b52e6c Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:01:54 -0500 Subject: [PATCH 2/9] app_containers: Use UID instead of username for $run_as Note that we still assume the user name inside the container is `user`. --- app_containers/.local/bin/run_app_container | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index 003021a..5fb485c 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -8,8 +8,8 @@ die() { exit() { rm -rf "$container_xdg_runtime" if [ "$CONTAINER_USE_USERNS" = true ]; then - setfacl -x u:$((private_users + 1000)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY - xhost -si:localuser:\#$((private_users + 1000)) + setfacl -x u:$((private_users + run_as)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY + xhost -si:localuser:\#$((private_users + run_as)) fi } @@ -45,11 +45,13 @@ fi [ -S $host_pulse ] || die "PulseAudio UNIX socket not found" -# Default username (assume `user` always has the same uid as the host user) -run_as=user +# Default user +run_as=$UID +# We assume the user named `user` inside the container always has the same UID as +# the user with uid $run_as on the host; this is currently not yet configurable homedir=/home/user if [ "$CONTAINER_RUN_AS_ROOT" = true ]; then - run_as=root + run_as=0 homedir=/root fi @@ -61,8 +63,8 @@ if [ "$CONTAINER_USE_USERNS" = true ]; then private_users=$(shuf -i 65536-$((2147483647 - 65536)) -n1) # Pick a random starting offset bind_opts="idmap" # Note: custom mounts specified by the user are expected to incldue the idmap option as well # Grant the user inside the namespace access to the Wayland / Xorg display - setfacl -m u:$((private_users + 1000)):rwx $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY - xhost +si:localuser:\#$((private_users + 1000)) + setfacl -m u:$((private_users + run_as)):rwx $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY + xhost +si:localuser:\#$((private_users + run_as)) fi SUDO_ASKPASS=$HOME/.local/bin/askpass-bemenu sudo -A systemd-nspawn -M $CONTAINER_NAME \ From 8aa252305dd57c3baeb1e112f3846685a0321124 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:04:35 -0500 Subject: [PATCH 3/9] app_containers: Define SUDO_ASKPASS first --- app_containers/.local/bin/run_app_container | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index 5fb485c..011a4a8 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -16,6 +16,10 @@ exit() { [ -z "$CONTAINER_NAME" ] && die "\$CONTAINER_NAME not set" [ -z "$DISPLAY" ] && die "\$DISPLAY not set (you must run the script in a desktop environment" +# Use a GUI-available askpass program for sudo +# This should be made configurable +export SUDO_ASKPASS=$HOME/.local/bin/askpass-bemenu + # Source configuration files if any config="$HOME/.config/app_containers/$CONTAINER_NAME.sh" if [ -f "$config" ]; then @@ -67,7 +71,7 @@ if [ "$CONTAINER_USE_USERNS" = true ]; then xhost +si:localuser:\#$((private_users + run_as)) fi -SUDO_ASKPASS=$HOME/.local/bin/askpass-bemenu sudo -A systemd-nspawn -M $CONTAINER_NAME \ +sudo -A systemd-nspawn -M $CONTAINER_NAME \ --private-users=$private_users --private-users-ownership=map \ `# DNS (when containers do not have their own netns)` \ --bind-ro=/run/systemd/resolve/stub-resolv.conf:/etc/resolv.conf \ From fd3fcf1e36463594841a4405dc6d91cf4b5eccdb Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:08:55 -0500 Subject: [PATCH 4/9] app_containers: Detect the user home directory dynamically ...so that we can stop assuming the username inside the container (although the shortcut generation script still does, but we'll fix that later, hopefully) --- app_containers/.local/bin/run_app_container | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index 011a4a8..c59a061 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -51,14 +51,18 @@ fi # Default user run_as=$UID -# We assume the user named `user` inside the container always has the same UID as -# the user with uid $run_as on the host; this is currently not yet configurable -homedir=/home/user if [ "$CONTAINER_RUN_AS_ROOT" = true ]; then run_as=0 - homedir=/root fi +homedir=/ +for line in $(sudo cat /var/lib/machines/$CONTAINER_NAME/etc/passwd); do + if [ "$(echo "$line" | cut -d: -f3)" == "$run_as" ]; then + homedir="$(echo "$line" | cut -d: -f6)" + break + fi +done + # Userns-related config # Default to identity mapping, which does not provide uid isolation but does for capabilities private_users=identity From da9414d4a8607b6f3a2b179010ac3ef5243ac280 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:14:32 -0500 Subject: [PATCH 5/9] app_containers: Properly support different UID on host / in container We simply use the same logic as the user namespaced case. --- app_containers/.local/bin/run_app_container | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index c59a061..fba06b2 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -7,10 +7,9 @@ die() { exit() { rm -rf "$container_xdg_runtime" - if [ "$CONTAINER_USE_USERNS" = true ]; then - setfacl -x u:$((private_users + run_as)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY - xhost -si:localuser:\#$((private_users + run_as)) - fi + # Remove the temporary facl-based permissions + setfacl -x u:$((user_on_host)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY + xhost -si:localuser:\#$((user_on_host)) } [ -z "$CONTAINER_NAME" ] && die "\$CONTAINER_NAME not set" @@ -67,14 +66,19 @@ done # Default to identity mapping, which does not provide uid isolation but does for capabilities private_users=identity bind_opts="" +user_on_host=$run_as if [ "$CONTAINER_USE_USERNS" = true ]; then private_users=$(shuf -i 65536-$((2147483647 - 65536)) -n1) # Pick a random starting offset bind_opts="idmap" # Note: custom mounts specified by the user are expected to incldue the idmap option as well - # Grant the user inside the namespace access to the Wayland / Xorg display - setfacl -m u:$((private_users + run_as)):rwx $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY - xhost +si:localuser:\#$((private_users + run_as)) + user_on_host=$((private_users + run_as)) fi +# Grant the user inside the container access to the Wayland / Xorg display +# For the Wayland socket, a simple facl rule would suffice +# For Xorg, we need to use the `xhost` facilities +setfacl -m u:$user_on_host:rwx $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY +xhost +si:localuser:\#$user_on_host + sudo -A systemd-nspawn -M $CONTAINER_NAME \ --private-users=$private_users --private-users-ownership=map \ `# DNS (when containers do not have their own netns)` \ From edddafda266229c96fa93d28bf255a094b6147bb Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:20:03 -0500 Subject: [PATCH 6/9] app_containers: Grant input devices access to inside the container --- app_containers/.local/bin/run_app_container | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index fba06b2..147b1a8 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -10,6 +10,10 @@ exit() { # Remove the temporary facl-based permissions setfacl -x u:$((user_on_host)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY xhost -si:localuser:\#$((user_on_host)) + + for input in $(find /dev/input -type c); do + sudo setfacl -x u:$user_on_host $input + done } [ -z "$CONTAINER_NAME" ] && die "\$CONTAINER_NAME not set" @@ -79,6 +83,13 @@ fi setfacl -m u:$user_on_host:rwx $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY xhost +si:localuser:\#$user_on_host +# Grant the user inside the container access to input devices +# Note: any new device plugged in when the container is running would not +# be added properly here. +for input in $(find /dev/input -type c); do + sudo setfacl -m u:$user_on_host:rw- $input +done + sudo -A systemd-nspawn -M $CONTAINER_NAME \ --private-users=$private_users --private-users-ownership=map \ `# DNS (when containers do not have their own netns)` \ From 8ce1f690b7c9c4bf9da4420c10655a9a5c35d13b Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:21:20 -0500 Subject: [PATCH 7/9] app_containers: Force the use of SUDO_ASKPASS --- app_containers/.local/bin/run_app_container | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index 147b1a8..44d5894 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -59,7 +59,7 @@ if [ "$CONTAINER_RUN_AS_ROOT" = true ]; then fi homedir=/ -for line in $(sudo cat /var/lib/machines/$CONTAINER_NAME/etc/passwd); do +for line in $(sudo -A cat /var/lib/machines/$CONTAINER_NAME/etc/passwd); do if [ "$(echo "$line" | cut -d: -f3)" == "$run_as" ]; then homedir="$(echo "$line" | cut -d: -f6)" break @@ -87,7 +87,7 @@ xhost +si:localuser:\#$user_on_host # Note: any new device plugged in when the container is running would not # be added properly here. for input in $(find /dev/input -type c); do - sudo setfacl -m u:$user_on_host:rw- $input + sudo -A setfacl -m u:$user_on_host:rw- $input done sudo -A systemd-nspawn -M $CONTAINER_NAME \ From 19f37e343bbe2ec43698384e08f60e98aabe4627 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:22:16 -0500 Subject: [PATCH 8/9] app_containers: Rename the cleanup routine to cleanup() exit is actually a keyword in bash --- app_containers/.local/bin/run_app_container | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index 44d5894..5aabae3 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -5,7 +5,7 @@ die() { exit 1 } -exit() { +cleanup() { rm -rf "$container_xdg_runtime" # Remove the temporary facl-based permissions setfacl -x u:$((user_on_host)) $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY @@ -31,7 +31,7 @@ fi # Create a XDG_RUNTIME_DIR for guest on host container_xdg_runtime="$(mktemp -d -p /var/tmp)" -trap exit EXIT +trap cleanup EXIT # Link the current wayland session to the container's xdg runtime # Note that the session itself must be bind-mounted first From edcfaef386495f1b9c62e8cce78478fd00ed9ce7 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 31 Dec 2022 15:26:51 -0500 Subject: [PATCH 9/9] app_containers: Move to using CONTAINER_BIND_MOUNTS for extra binds ...instead of the overly generic SYSTEMD_NSPAWN_EXTRA_ARGS variable. --- app_containers/.local/bin/run_app_container | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app_containers/.local/bin/run_app_container b/app_containers/.local/bin/run_app_container index 5aabae3..0d08a15 100755 --- a/app_containers/.local/bin/run_app_container +++ b/app_containers/.local/bin/run_app_container @@ -73,7 +73,7 @@ bind_opts="" user_on_host=$run_as if [ "$CONTAINER_USE_USERNS" = true ]; then private_users=$(shuf -i 65536-$((2147483647 - 65536)) -n1) # Pick a random starting offset - bind_opts="idmap" # Note: custom mounts specified by the user are expected to incldue the idmap option as well + bind_opts="idmap" user_on_host=$((private_users + run_as)) fi @@ -90,6 +90,12 @@ for input in $(find /dev/input -type c); do sudo -A setfacl -m u:$user_on_host:rw- $input done +# Bind-mounts defined by the user (possibly in the container-specific config file) +# Format should be "src:target". target cannot be omitted +for mount in ${CONTAINER_BIND_MOUNTS[@]}; do + SYSTEMD_NSPAWN_EXTRA_ARGS+=" --bind=$mount:$bind_opts" +done + sudo -A systemd-nspawn -M $CONTAINER_NAME \ --private-users=$private_users --private-users-ownership=map \ `# DNS (when containers do not have their own netns)` \