#!/usr/bin/env bash # SPDX-License-Identifier: GPL-3.0-or-later # Caller must already be in private mount/PID namespaces. # A plain chroot makes CLONE_NEWUSER fail with EPERM inside sbuild. set -euo pipefail (( EUID == 0 )) || exit 1 root_dir=${1:?} work_dir=${2:?} account=${3:?} shift 3 [[ $account == root || $account == builder ]] [[ -f $root_dir/etc/debian_version && -d $work_dir ]] [[ ! -L $root_dir && ! -L $root_dir/etc/resolv.conf ]] [[ $(readlink /proc/self/ns/mnt) != $(readlink /proc/1/ns/mnt) ]] || { echo 'enter-root requires the private mount namespace created by its wrapper.' >&2 exit 1 } mount --make-rprivate / mount --bind "$root_dir" "$root_dir" mkdir -p "$root_dir"/{proc,sys,dev,run,tmp,work} mount -t proc -o nosuid,nodev,noexec proc "$root_dir/proc" mount -t sysfs -o ro,nosuid,nodev,noexec sysfs "$root_dir/sys" mount -t tmpfs -o mode=755,nosuid tmpfs "$root_dir/dev" for device in null zero full random urandom tty; do touch "$root_dir/dev/$device" mount --bind "/dev/$device" "$root_dir/dev/$device" done mkdir -p "$root_dir/dev/pts" "$root_dir/dev/shm" mount -t devpts -o newinstance,ptmxmode=0666,mode=0620 devpts "$root_dir/dev/pts" mount -t tmpfs -o mode=1777,nosuid,nodev tmpfs "$root_dir/dev/shm" ln -s pts/ptmx "$root_dir/dev/ptmx" ln -s /proc/self/fd "$root_dir/dev/fd" ln -s /proc/self/fd/0 "$root_dir/dev/stdin" ln -s /proc/self/fd/1 "$root_dir/dev/stdout" ln -s /proc/self/fd/2 "$root_dir/dev/stderr" mount -t tmpfs -o mode=755,nosuid,nodev tmpfs "$root_dir/run" mount -t tmpfs -o mode=1777,nosuid,nodev tmpfs "$root_dir/tmp" mount --bind "$work_dir" "$root_dir/work" cat /etc/resolv.conf > "$root_dir/etc/resolv.conf" mkdir "$root_dir/run/.old-root" cd "$root_dir" pivot_root . run/.old-root cd / umount --lazy /run/.old-root rmdir /run/.old-root user_home=/home/builder [[ $account != root ]] || user_home=/root command=(/usr/bin/env -i HOME="$user_home" USER="$account" LOGNAME="$account" PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LANG=C.UTF-8 LC_ALL=C.UTF-8 TERM="${TERM:-dumb}" /bin/bash --noprofile --norc -c 'cd /work; exec "$@"' bash "$@") if [[ $account == root ]]; then exec "${command[@]}" else exec setpriv --reuid=builder --regid=builder --init-groups "${command[@]}" fi