#!/bin/bash # Ladill jailed shell for the hosting browser terminal. Per session (private mount # ns): /home holds only this user's dir, and /etc/passwd|group expose only root + # this user. The customer can never see other tenants, the host fs, or secrets. # Usage: ladill-jailsh [relpath] set -euo pipefail JAIL=/home/jail U=${1:-} REL=${2:-/public_html} [ -n "$U" ] || { echo 'usage: ladill-jailsh [relpath]'; exit 2; } UID_=$(id -u "$U" 2>/dev/null || true) GID_=$(id -g "$U" 2>/dev/null || true) [ -n "$UID_" ] && [ "$UID_" -ge 1000 ] || { echo 'refusing: not a hosting user'; exit 1; } HOMEDIR=/home/$U [ -d "$HOMEDIR" ] || { echo 'no home directory'; exit 1; } case "$REL" in *..*) REL=/public_html;; esac if [ -z "${LADILL_JAIL_NS:-}" ]; then exec env LADILL_JAIL_NS=1 unshare --mount --propagation private -- "$0" "$U" "$REL" fi # /home with only this user's directory mount -t tmpfs -o mode=0755,nosuid,nodev tmpfs "$JAIL/home" mkdir -p "$JAIL/home/$U" mount --bind "$HOMEDIR" "$JAIL/home/$U" # passwd/group exposing only root + this user (no tenant enumeration) mount -t tmpfs -o mode=0755,nosuid,nodev tmpfs "$JAIL/run" { echo 'root:x:0:0:root:/root:/bin/bash'; getent passwd "$U"; } > "$JAIL/run/passwd" { echo 'root:x:0:'; getent group "$U"; } > "$JAIL/run/group" mount --bind "$JAIL/run/passwd" "$JAIL/etc/passwd" mount --bind "$JAIL/run/group" "$JAIL/etc/group" export HOME="/home/$U" USER="$U" LOGNAME="$U" SHELL=/bin/bash PATH=/usr/bin:/bin export TERM="${TERM:-xterm-256color}" LADILL_START_DIR="/home/$U$REL" HOSTNAME="$(hostname 2>/dev/null || echo ladill)" exec /usr/sbin/chroot --userspec="$UID_:$GID_" "$JAIL" /bin/bash --rcfile /etc/ladill-jail-bashrc -i