57 lines
2.2 KiB
Bash
57 lines
2.2 KiB
Bash
#!/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
|