#!/bin/sh set -eu cc_bin=${CC_BIN:-/usr/bin/cc} uid1=${BUILD_UID1:-35001} gid1=${BUILD_GID1:-35001} uid2=${BUILD_UID2:-35002} gid2=${BUILD_GID2:-35002} hold_seconds=${HOLD_SECONDS:-2} cleanup_workdir=0 mount_points= jail_ids= if [ -n "${WORKDIR:-}" ]; then workdir=$WORKDIR mkdir -p "$workdir" else workdir=$(mktemp -d /tmp/fruix-privdrop-prototype.XXXXXX) cleanup_workdir=1 fi if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then cleanup_workdir=0 fi record_mount() { mount_points="$1 $mount_points" } record_jail() { jail_ids="$1 $jail_ids" } cleanup() { set +e old_ifs=$IFS IFS=' ' for jail_id in $jail_ids; do [ -n "$jail_id" ] || continue sudo jail -r "$jail_id" >/dev/null 2>&1 || true done for mount_point in $mount_points; do [ -n "$mount_point" ] || continue sudo umount "$mount_point" >/dev/null 2>&1 || true done IFS=$old_ifs if [ "$cleanup_workdir" -eq 1 ]; then sudo rm -rf "$workdir" fi } trap cleanup EXIT INT TERM helper_src=tests/daemon/freebsd-build-user-helper.c helper_bin=$workdir/tools/freebsd-build-user-helper protected_dir=$workdir/protected outside_sentinel=$workdir/outside-sentinel metadata_file=$workdir/freebsd-privdrop-metadata.txt helper_compile_log=$workdir/helper-compile.log helper_compile_err=$workdir/helper-compile.err job1_out=$workdir/job1.out job1_err=$workdir/job1.err job2_out=$workdir/job2.out job2_err=$workdir/job2.err job1_stat=$workdir/job1.stat job2_stat=$workdir/job2.stat mkdir -p "$workdir/tools" "$protected_dir" "$workdir/job1-host" "$workdir/job2-host" printf 'host-only-outside-sentinel\n' > "$outside_sentinel" printf 'protected-root-owned\n' > "$protected_dir/root-note.txt" chmod 0755 "$protected_dir" chmod 0644 "$protected_dir/root-note.txt" "$cc_bin" -Wall -Wextra -std=c11 "$helper_src" -o "$helper_bin" >"$helper_compile_log" 2>"$helper_compile_err" prepare_job_tree() { job_name=$1 job_uid=$2 job_gid=$3 peer_uid=$4 peer_gid=$5 job_host=$workdir/$job_name-host root=$job_host/root work_mount=$job_host/work peer_mount=$job_host/peer mkdir -p "$root/tools" "$root/protected" "$root/work" "$root/peer" "$root/tmp" "$work_mount" "$peer_mount" chmod 1777 "$root/tmp" printf '%s-allowed\n' "$job_name" > "$work_mount/allowed.txt" printf '%s-secret\n' "$job_name" > "$work_mount/secret.txt" chmod 0600 "$work_mount/allowed.txt" "$work_mount/secret.txt" chmod 0700 "$work_mount" sudo chown -R "$job_uid:$job_gid" "$work_mount" printf 'peer-for-%s\n' "$job_name" > "$peer_mount/secret.txt" chmod 0600 "$peer_mount/secret.txt" chmod 0700 "$peer_mount" sudo chown -R "$peer_uid:$peer_gid" "$peer_mount" for host_path in /lib /libexec; do sudo mkdir -p "$root$host_path" sudo mount_nullfs -o ro "$host_path" "$root$host_path" record_mount "$root$host_path" done sudo mount_nullfs -o ro "$workdir/tools" "$root/tools" record_mount "$root/tools" sudo mount_nullfs "$work_mount" "$root/work" record_mount "$root/work" sudo mount_nullfs -o ro "$peer_mount" "$root/peer" record_mount "$root/peer" sudo mount_nullfs "$protected_dir" "$root/protected" record_mount "$root/protected" jail_name=fruix-privdrop-$job_name-$$ jail_id=$(sudo jail -i -c \ name="$jail_name" \ path="$root" \ host.hostname="$jail_name" \ persist \ ip4=disable \ ip6=disable) record_jail "$jail_id" printf '%s\n' "$jail_id" > "$job_host/jid" } prepare_job_tree job1 "$uid1" "$gid1" "$uid2" "$gid2" prepare_job_tree job2 "$uid2" "$gid2" "$uid1" "$gid1" jid1=$(cat "$workdir/job1-host/jid") jid2=$(cat "$workdir/job2-host/jid") start_epoch=$(date +%s) sudo jexec "$jid1" /tools/freebsd-build-user-helper \ --job-name job1 \ --uid "$uid1" \ --gid "$gid1" \ --allowed-file /work/allowed.txt \ --own-output /work/result.txt \ --peer-file /peer/secret.txt \ --hidden-file /outside-sentinel \ --protected-file /protected/escape-job1 \ --hold-seconds "$hold_seconds" >"$job1_out" 2>"$job1_err" & pid1=$! sudo jexec "$jid2" /tools/freebsd-build-user-helper \ --job-name job2 \ --uid "$uid2" \ --gid "$gid2" \ --allowed-file /work/allowed.txt \ --own-output /work/result.txt \ --peer-file /peer/secret.txt \ --hidden-file /outside-sentinel \ --protected-file /protected/escape-job2 \ --hold-seconds "$hold_seconds" >"$job2_out" 2>"$job2_err" & pid2=$! set +e wait "$pid1" rc1=$? wait "$pid2" rc2=$? set -e end_epoch=$(date +%s) elapsed=$((end_epoch - start_epoch)) if [ "$rc1" -ne 0 ] || [ "$rc2" -ne 0 ]; then echo "freebsd privilege-drop prototype failed" >&2 cat "$job1_out" >&2 || true cat "$job1_err" >&2 || true cat "$job2_out" >&2 || true cat "$job2_err" >&2 || true exit 1 fi sudo stat -f '%Su %Sg %u %g %Sp' "$workdir/job1-host/work/result.txt" > "$job1_stat" sudo stat -f '%Su %Sg %u %g %Sp' "$workdir/job2-host/work/result.txt" > "$job2_stat" cat > "$metadata_file" <