Jailed terminal: per-session passwd so customers can't enumerate tenants
Deploy Ladill Hosting / deploy (push) Successful in 39s
Deploy Ladill Hosting / deploy (push) Successful in 39s
The jail's /etc/passwd listed every hosting username (no passwords — shadow isn't in the jail — but it enumerated tenants). The launcher now binds a per-session /etc/passwd|group (root + the current user only) inside each session's mount namespace, and the shared jail passwd no longer carries hosting users. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f7bba4d453
commit
d54ae879b6
@@ -1,8 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Ladill jailed shell for the hosting browser terminal. Confines a hosting
|
# Ladill jailed shell for the hosting browser terminal. Per session (private mount
|
||||||
# account to /home/jail with ONLY its own home visible: a private mount namespace
|
# ns): /home holds only this user's dir, and /etc/passwd|group expose only root +
|
||||||
# plus a per-session tmpfs /home that contains just this user's directory (so
|
# this user. The customer can never see other tenants, the host fs, or secrets.
|
||||||
# 'ls /home' shows their own folder and never other tenants).
|
|
||||||
# Usage: ladill-jailsh <username> [relpath]
|
# Usage: ladill-jailsh <username> [relpath]
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
JAIL=/home/jail
|
JAIL=/home/jail
|
||||||
@@ -15,14 +14,19 @@ GID_=$(id -g "$U" 2>/dev/null || true)
|
|||||||
HOMEDIR=/home/$U
|
HOMEDIR=/home/$U
|
||||||
[ -d "$HOMEDIR" ] || { echo 'no home directory'; exit 1; }
|
[ -d "$HOMEDIR" ] || { echo 'no home directory'; exit 1; }
|
||||||
case "$REL" in *..*) REL=/public_html;; esac
|
case "$REL" in *..*) REL=/public_html;; esac
|
||||||
# re-exec into a private mount namespace so all mounts are per-session
|
|
||||||
if [ -z "${LADILL_JAIL_NS:-}" ]; then
|
if [ -z "${LADILL_JAIL_NS:-}" ]; then
|
||||||
exec env LADILL_JAIL_NS=1 unshare --mount --propagation private -- "$0" "$U" "$REL"
|
exec env LADILL_JAIL_NS=1 unshare --mount --propagation private -- "$0" "$U" "$REL"
|
||||||
fi
|
fi
|
||||||
# Fresh, listable /home holding ONLY this user's directory (no tenant leak).
|
# /home with only this user's directory
|
||||||
mount -t tmpfs -o mode=0755,nosuid,nodev tmpfs "$JAIL/home"
|
mount -t tmpfs -o mode=0755,nosuid,nodev tmpfs "$JAIL/home"
|
||||||
mkdir -p "$JAIL/home/$U"
|
mkdir -p "$JAIL/home/$U"
|
||||||
mount --bind "$HOMEDIR" "$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 HOME="/home/$U" USER="$U" LOGNAME="$U" SHELL=/bin/bash PATH=/usr/bin:/bin
|
||||||
export TERM="${TERM:-xterm-256color}"
|
export TERM="${TERM:-xterm-256color}"
|
||||||
exec /usr/sbin/chroot --userspec="$UID_:$GID_" "$JAIL" /bin/bash -l -c "cd '/home/$U$REL' 2>/dev/null || cd ~; exec /bin/bash -l"
|
exec /usr/sbin/chroot --userspec="$UID_:$GID_" "$JAIL" /bin/bash -l -c "cd '/home/$U$REL' 2>/dev/null || cd ~; exec /bin/bash -l"
|
||||||
|
|||||||
@@ -23,13 +23,9 @@ cp -rn /usr/share/terminfo/x "$JAIL/usr/share/terminfo/" 2>/dev/null || true
|
|||||||
install -d -o root -g root -m 711 "$JAIL/home"
|
install -d -o root -g root -m 711 "$JAIL/home"
|
||||||
install -d -m 1777 "$JAIL/tmp"
|
install -d -m 1777 "$JAIL/tmp"
|
||||||
|
|
||||||
echo "==> Syncing hosting users into the jail passwd/group (for name resolution)"
|
# NOTE: do NOT sync hosting users into the shared jail passwd — that would let
|
||||||
while IFS=: read -r name _ uid gid _ home shell; do
|
# any customer enumerate every tenant. ladill-jailsh injects a per-session
|
||||||
[ "$uid" -ge 1000 ] 2>/dev/null || continue
|
# passwd/group (root + the current user only) inside each session's namespace.
|
||||||
[ -d "/home/$name" ] || continue
|
|
||||||
grep -q "^$name:" "$JAIL/etc/passwd" || getent passwd "$name" >> "$JAIL/etc/passwd"
|
|
||||||
grep -q "^$name:" "$JAIL/etc/group" || getent group "$name" >> "$JAIL/etc/group"
|
|
||||||
done < <(getent passwd)
|
|
||||||
|
|
||||||
echo "==> Installing the jailed-shell launcher + scoped sudoers"
|
echo "==> Installing the jailed-shell launcher + scoped sudoers"
|
||||||
install -o root -g root -m 755 "$(dirname "$0")/ladill-jailsh" /usr/local/sbin/ladill-jailsh
|
install -o root -g root -m 755 "$(dirname "$0")/ladill-jailsh" /usr/local/sbin/ladill-jailsh
|
||||||
|
|||||||
Reference in New Issue
Block a user