Fix capabilities
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
name=skz-sloptrap
|
||||
packages_extra=bash make shellcheck jq podman
|
||||
packages_extra=bash make shellcheck jq podman iproute2 strace
|
||||
capabilities=apt-install nested-podman packet-capture
|
||||
allow_host_network=false
|
||||
|
||||
538
sloptrap
538
sloptrap
@@ -370,13 +370,23 @@ if [[ $# -eq 0 ]]; then
|
||||
fi
|
||||
|
||||
if [[ $(id -u) -eq 0 ]]; then
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/run/sloptrap-helper}
|
||||
mkdir -p "$helper_dir/queue"
|
||||
chmod 700 "$helper_dir"
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/tmp/sloptrap-helper}
|
||||
queue_dir="$helper_dir/queue"
|
||||
mkdir -p "$queue_dir"
|
||||
chmod 711 "$helper_dir"
|
||||
chmod 700 "$queue_dir"
|
||||
target_uid=${SLOPTRAP_HOST_UID:-}
|
||||
target_gid=${SLOPTRAP_HOST_GID:-}
|
||||
if [[ -n $target_uid && -n $target_gid ]]; then
|
||||
chown "$target_uid:$target_gid" "$queue_dir"
|
||||
fi
|
||||
if [[ -n ${SLOPTRAP_ACTIVE_CAPABILITIES:-} ]]; then
|
||||
/usr/local/bin/sloptrap-helperd &
|
||||
helper_pid=$!
|
||||
fi
|
||||
if [[ -n $target_uid && -n $target_gid ]]; then
|
||||
exec setpriv --reuid "$target_uid" --regid "$target_gid" --clear-groups -- "$@"
|
||||
fi
|
||||
exec runuser -u sloptrap --preserve-environment -- "$@"
|
||||
fi
|
||||
|
||||
@@ -387,13 +397,25 @@ EOF
|
||||
cat <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
umask 077
|
||||
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/run/sloptrap-helper}
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/tmp/sloptrap-helper}
|
||||
queue_dir="$helper_dir/queue"
|
||||
caps=${SLOPTRAP_ACTIVE_CAPABILITIES:-}
|
||||
audit_log=${SLOPTRAP_AUDIT_LOG:-/codex/state/capabilities.log}
|
||||
capture_root=${SLOPTRAP_CAPTURE_DIR:-/codex/state/captures}
|
||||
workspace_root=${SLOPTRAP_WORKDIR:-/workspace}
|
||||
pidfile="$helper_dir/helperd.pid"
|
||||
mkdir -p "$queue_dir" "$(dirname "$audit_log")"
|
||||
|
||||
cleanup_pidfile() {
|
||||
rm -f "$pidfile"
|
||||
}
|
||||
|
||||
trap cleanup_pidfile EXIT INT TERM HUP
|
||||
printf '%s\n' "$$" >"$pidfile"
|
||||
chmod 644 "$pidfile" 2>/dev/null || true
|
||||
|
||||
has_capability() {
|
||||
local needle=$1
|
||||
local token
|
||||
@@ -412,6 +434,74 @@ log_action() {
|
||||
printf '%s op=%s status=%s %s\n' "$(date -u +%FT%TZ)" "$op" "$status" "$details" >>"$audit_log"
|
||||
}
|
||||
|
||||
resolve_path() {
|
||||
local raw=$1
|
||||
if command -v realpath >/dev/null 2>&1; then
|
||||
realpath -m "$raw"
|
||||
return
|
||||
fi
|
||||
case "$raw" in
|
||||
/*) printf '%s\n' "$raw" ;;
|
||||
*) printf '%s/%s\n' "$(pwd -P)" "$raw" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
path_within_root() {
|
||||
local root path
|
||||
root=$(resolve_path "$1")
|
||||
path=$(resolve_path "$2")
|
||||
case "$path" in
|
||||
"$root"|"${root}/"*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
claim_request_dir() {
|
||||
local request_dir=$1
|
||||
[[ -d $request_dir && ! -L $request_dir ]] || return 1
|
||||
path_within_root "$queue_dir" "$request_dir" || return 1
|
||||
chown root:root "$request_dir" 2>/dev/null || true
|
||||
chmod 700 "$request_dir" 2>/dev/null || true
|
||||
}
|
||||
|
||||
init_request_outputs() {
|
||||
local request_dir=$1
|
||||
local path
|
||||
[[ ! -e "$request_dir/status" && ! -L "$request_dir/status" ]] || return 1
|
||||
for path in "$request_dir/stdout" "$request_dir/stderr"; do
|
||||
[[ ! -L $path ]] || return 1
|
||||
rm -f "$path"
|
||||
: >"$path"
|
||||
chmod 600 "$path" 2>/dev/null || true
|
||||
done
|
||||
}
|
||||
|
||||
read_request_value() {
|
||||
local path=$1
|
||||
[[ -f $path && ! -L $path ]] || return 1
|
||||
cat "$path"
|
||||
}
|
||||
|
||||
validate_package_name() {
|
||||
local package=$1
|
||||
[[ $package =~ ^[A-Za-z0-9][A-Za-z0-9+.-]*$ ]]
|
||||
}
|
||||
|
||||
validate_packet_interface() {
|
||||
local iface=$1
|
||||
[[ $iface =~ ^[A-Za-z0-9][A-Za-z0-9_.:@+-]*$ ]]
|
||||
}
|
||||
|
||||
validate_capture_path() {
|
||||
local path=$1
|
||||
local resolved
|
||||
resolved=$(resolve_path "$path")
|
||||
path_within_root "$capture_root" "$resolved" && return 0
|
||||
path_within_root "$workspace_root" "$resolved"
|
||||
}
|
||||
|
||||
write_status() {
|
||||
local request_dir=$1
|
||||
local status=$2
|
||||
@@ -427,7 +517,7 @@ run_apt_install() {
|
||||
return
|
||||
}
|
||||
local packages_file="$request_dir/packages"
|
||||
if [[ ! -f $packages_file ]]; then
|
||||
if [[ ! -f $packages_file || -L $packages_file ]]; then
|
||||
printf 'missing package list\n' >"$request_dir/stderr"
|
||||
write_status "$request_dir" 2
|
||||
log_action "apt-install" "packages=missing" 2
|
||||
@@ -440,6 +530,15 @@ run_apt_install() {
|
||||
log_action "apt-install" "packages=empty" 2
|
||||
return
|
||||
fi
|
||||
local package
|
||||
for package in "${packages[@]}"; do
|
||||
if ! validate_package_name "$package"; then
|
||||
printf 'invalid package name %s\n' "$package" >"$request_dir/stderr"
|
||||
write_status "$request_dir" 2
|
||||
log_action "apt-install" "packages=invalid" 2
|
||||
return
|
||||
fi
|
||||
done
|
||||
if apt-get update >"$request_dir/stdout" 2>"$request_dir/stderr" \
|
||||
&& apt-get install -y --no-install-recommends "${packages[@]}" >>"$request_dir/stdout" 2>>"$request_dir/stderr"; then
|
||||
write_status "$request_dir" 0
|
||||
@@ -466,25 +565,47 @@ run_packet_capture() {
|
||||
return
|
||||
}
|
||||
local iface filter_file output_file stdout_mode
|
||||
iface=$(<"$iface_file")
|
||||
iface=$(read_request_value "$iface_file" || true)
|
||||
filter_file="$request_dir/filter"
|
||||
output_file="$request_dir/output"
|
||||
stdout_mode=0
|
||||
[[ -f "$request_dir/stdout_mode" ]] && stdout_mode=$(<"$request_dir/stdout_mode")
|
||||
local -a cmd=(tcpdump -i "$iface")
|
||||
if [[ -s $filter_file ]]; then
|
||||
local filter
|
||||
filter=$(<"$filter_file")
|
||||
local -a filter_tokens=()
|
||||
read -r -a filter_tokens <<< "$filter"
|
||||
cmd+=("${filter_tokens[@]}")
|
||||
[[ -f "$request_dir/stdout_mode" ]] && stdout_mode=$(read_request_value "$request_dir/stdout_mode" || true)
|
||||
if ! validate_packet_interface "$iface"; then
|
||||
printf 'invalid interface %s\n' "$iface" >"$request_dir/stderr"
|
||||
write_status "$request_dir" 2
|
||||
log_action "packet-capture" "interface=invalid" 2
|
||||
return
|
||||
fi
|
||||
if [[ $stdout_mode != "0" && $stdout_mode != "1" ]]; then
|
||||
printf 'invalid stdout mode %s\n' "$stdout_mode" >"$request_dir/stderr"
|
||||
write_status "$request_dir" 2
|
||||
log_action "packet-capture" "interface=$iface stdout=invalid" 2
|
||||
return
|
||||
fi
|
||||
local -a cmd=(tcpdump -i "$iface")
|
||||
if [[ -s $output_file ]]; then
|
||||
local capture_path
|
||||
capture_path=$(<"$output_file")
|
||||
capture_path=$(read_request_value "$output_file" || true)
|
||||
if ! validate_capture_path "$capture_path"; then
|
||||
printf 'output path must stay within %s or %s\n' "$capture_root" "$workspace_root" >"$request_dir/stderr"
|
||||
write_status "$request_dir" 2
|
||||
log_action "packet-capture" "interface=$iface output=invalid" 2
|
||||
return
|
||||
fi
|
||||
mkdir -p "$(dirname "$capture_path")"
|
||||
cmd+=(-w "$capture_path")
|
||||
fi
|
||||
if [[ -s $filter_file ]]; then
|
||||
local filter
|
||||
filter=$(read_request_value "$filter_file" || true)
|
||||
local -a filter_tokens=()
|
||||
if [[ -n $filter ]]; then
|
||||
read -r -a filter_tokens <<< "$filter"
|
||||
fi
|
||||
if [[ ${#filter_tokens[@]} -gt 0 ]]; then
|
||||
cmd+=(-- "${filter_tokens[@]}")
|
||||
fi
|
||||
fi
|
||||
if [[ $stdout_mode == "1" ]]; then
|
||||
"${cmd[@]}" >"$request_dir/stdout" 2>"$request_dir/stderr" || {
|
||||
write_status "$request_dir" 1
|
||||
@@ -506,6 +627,7 @@ while true; do
|
||||
shopt -s nullglob
|
||||
request_dirs=("$queue_dir"/*.req)
|
||||
shopt -u nullglob
|
||||
pending_requests=0
|
||||
if [[ ${#request_dirs[@]} -eq 0 ]]; then
|
||||
sleep 1
|
||||
continue
|
||||
@@ -513,9 +635,21 @@ while true; do
|
||||
for request_dir in "${request_dirs[@]}"; do
|
||||
[[ -d $request_dir ]] || continue
|
||||
[[ ! -f "$request_dir/status" ]] || continue
|
||||
op=$(<"$request_dir/op")
|
||||
: >"$request_dir/stdout"
|
||||
: >"$request_dir/stderr"
|
||||
pending_requests=1
|
||||
if ! claim_request_dir "$request_dir"; then
|
||||
log_action "request" "unsafe=1 path=$request_dir" 2
|
||||
continue
|
||||
fi
|
||||
if ! init_request_outputs "$request_dir"; then
|
||||
log_action "request" "unsafe-output=1 path=$request_dir" 2
|
||||
continue
|
||||
fi
|
||||
if ! op=$(read_request_value "$request_dir/op"); then
|
||||
printf 'missing operation\n' >"$request_dir/stderr"
|
||||
write_status "$request_dir" 2
|
||||
log_action "request" "op=missing" 2
|
||||
continue
|
||||
fi
|
||||
case "$op" in
|
||||
apt-install)
|
||||
run_apt_install "$request_dir"
|
||||
@@ -530,6 +664,9 @@ while true; do
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [[ $pending_requests -eq 0 ]]; then
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
EOF
|
||||
;;
|
||||
@@ -538,9 +675,68 @@ EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/run/sloptrap-helper}
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/tmp/sloptrap-helper}
|
||||
queue_dir="$helper_dir/queue"
|
||||
mkdir -p "$queue_dir"
|
||||
pidfile="$helper_dir/helperd.pid"
|
||||
|
||||
helper_running() {
|
||||
local pid
|
||||
[[ -r $pidfile ]] || return 1
|
||||
pid=$(<"$pidfile")
|
||||
[[ -n $pid ]] || return 1
|
||||
kill -0 "$pid" 2>/dev/null
|
||||
}
|
||||
|
||||
ensure_helper_ready() {
|
||||
if [[ -w $queue_dir ]] && helper_running; then
|
||||
return 0
|
||||
fi
|
||||
if [[ -z ${SLOPTRAP_ACTIVE_CAPABILITIES:-} ]]; then
|
||||
printf 'slop-apt: capability helper is not available in this session\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v setpriv >/dev/null 2>&1; then
|
||||
printf 'slop-apt: setpriv is required to bootstrap the capability helper\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
setpriv --reuid 0 --regid 0 --clear-groups -- env \
|
||||
SLOPTRAP_HELPER_DIR="$helper_dir" \
|
||||
SLOPTRAP_ACTIVE_CAPABILITIES="${SLOPTRAP_ACTIVE_CAPABILITIES:-}" \
|
||||
SLOPTRAP_AUDIT_LOG="${SLOPTRAP_AUDIT_LOG:-/codex/state/capabilities.log}" \
|
||||
SLOPTRAP_CAPTURE_DIR="${SLOPTRAP_CAPTURE_DIR:-/codex/state/captures}" \
|
||||
SLOPTRAP_WORKDIR="${SLOPTRAP_WORKDIR:-/workspace}" \
|
||||
SLOPTRAP_HOST_UID="${SLOPTRAP_HOST_UID:-$(id -u)}" \
|
||||
SLOPTRAP_HOST_GID="${SLOPTRAP_HOST_GID:-$(id -g)}" \
|
||||
bash -c '
|
||||
set -euo pipefail
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/tmp/sloptrap-helper}
|
||||
queue_dir="$helper_dir/queue"
|
||||
pidfile="$helper_dir/helperd.pid"
|
||||
helper_bin=$(command -v sloptrap-helperd)
|
||||
[[ -n $helper_bin ]] || exit 1
|
||||
mkdir -p "$queue_dir"
|
||||
chmod 711 "$helper_dir"
|
||||
chmod 700 "$queue_dir"
|
||||
chown "$SLOPTRAP_HOST_UID:$SLOPTRAP_HOST_GID" "$queue_dir"
|
||||
if [[ -r $pidfile ]]; then
|
||||
pid=$(<"$pidfile")
|
||||
if [[ -n $pid ]] && kill -0 "$pid" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
"$helper_bin" >/dev/null 2>&1 &
|
||||
for ((i=0; i<30; i+=1)); do
|
||||
if [[ -r $pidfile ]]; then
|
||||
pid=$(<"$pidfile")
|
||||
if [[ -n $pid ]] && kill -0 "$pid" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
exit 1
|
||||
'
|
||||
}
|
||||
|
||||
if [[ ${1-} != "install" ]]; then
|
||||
printf 'usage: slop-apt install <package...>\n' >&2
|
||||
@@ -554,12 +750,14 @@ if [[ $# -eq 0 ]]; then
|
||||
fi
|
||||
|
||||
for package in "$@"; do
|
||||
if [[ ! $package =~ ^[A-Za-z0-9+.-]+$ ]]; then
|
||||
if [[ ! $package =~ ^[A-Za-z0-9][A-Za-z0-9+.-]*$ ]]; then
|
||||
printf 'slop-apt: invalid package name %s\n' "$package" >&2
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
|
||||
ensure_helper_ready
|
||||
|
||||
request_dir=$(mktemp -d "$queue_dir/request.XXXXXX.req")
|
||||
trap 'rm -rf "$request_dir"' EXIT INT TERM HUP
|
||||
printf 'apt-install\n' >"$request_dir/op"
|
||||
@@ -585,10 +783,97 @@ EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/run/sloptrap-helper}
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/tmp/sloptrap-helper}
|
||||
queue_dir="$helper_dir/queue"
|
||||
default_output=${SLOPTRAP_CAPTURE_DIR:-/codex/state/captures}
|
||||
mkdir -p "$queue_dir" "$default_output"
|
||||
workspace_root=${SLOPTRAP_WORKDIR:-/workspace}
|
||||
pidfile="$helper_dir/helperd.pid"
|
||||
mkdir -p "$default_output"
|
||||
|
||||
helper_running() {
|
||||
local pid
|
||||
[[ -r $pidfile ]] || return 1
|
||||
pid=$(<"$pidfile")
|
||||
[[ -n $pid ]] || return 1
|
||||
kill -0 "$pid" 2>/dev/null
|
||||
}
|
||||
|
||||
ensure_helper_ready() {
|
||||
if [[ -w $queue_dir ]] && helper_running; then
|
||||
return 0
|
||||
fi
|
||||
if [[ -z ${SLOPTRAP_ACTIVE_CAPABILITIES:-} ]]; then
|
||||
printf 'slopcap: capability helper is not available in this session\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v setpriv >/dev/null 2>&1; then
|
||||
printf 'slopcap: setpriv is required to bootstrap the capability helper\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
setpriv --reuid 0 --regid 0 --clear-groups -- env \
|
||||
SLOPTRAP_HELPER_DIR="$helper_dir" \
|
||||
SLOPTRAP_ACTIVE_CAPABILITIES="${SLOPTRAP_ACTIVE_CAPABILITIES:-}" \
|
||||
SLOPTRAP_AUDIT_LOG="${SLOPTRAP_AUDIT_LOG:-/codex/state/capabilities.log}" \
|
||||
SLOPTRAP_CAPTURE_DIR="${SLOPTRAP_CAPTURE_DIR:-/codex/state/captures}" \
|
||||
SLOPTRAP_WORKDIR="${SLOPTRAP_WORKDIR:-/workspace}" \
|
||||
SLOPTRAP_HOST_UID="${SLOPTRAP_HOST_UID:-$(id -u)}" \
|
||||
SLOPTRAP_HOST_GID="${SLOPTRAP_HOST_GID:-$(id -g)}" \
|
||||
bash -c '
|
||||
set -euo pipefail
|
||||
helper_dir=${SLOPTRAP_HELPER_DIR:-/tmp/sloptrap-helper}
|
||||
queue_dir="$helper_dir/queue"
|
||||
pidfile="$helper_dir/helperd.pid"
|
||||
helper_bin=$(command -v sloptrap-helperd)
|
||||
[[ -n $helper_bin ]] || exit 1
|
||||
mkdir -p "$queue_dir"
|
||||
chmod 711 "$helper_dir"
|
||||
chmod 700 "$queue_dir"
|
||||
chown "$SLOPTRAP_HOST_UID:$SLOPTRAP_HOST_GID" "$queue_dir"
|
||||
if [[ -r $pidfile ]]; then
|
||||
pid=$(<"$pidfile")
|
||||
if [[ -n $pid ]] && kill -0 "$pid" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
"$helper_bin" >/dev/null 2>&1 &
|
||||
for ((i=0; i<30; i+=1)); do
|
||||
if [[ -r $pidfile ]]; then
|
||||
pid=$(<"$pidfile")
|
||||
if [[ -n $pid ]] && kill -0 "$pid" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
exit 1
|
||||
'
|
||||
}
|
||||
|
||||
resolve_requested_path() {
|
||||
local raw=$1
|
||||
if command -v realpath >/dev/null 2>&1; then
|
||||
realpath -m "$raw"
|
||||
return
|
||||
fi
|
||||
case "$raw" in
|
||||
/*) printf '%s\n' "$raw" ;;
|
||||
*) printf '%s/%s\n' "$(pwd -P)" "$raw" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_output_path() {
|
||||
local path=$1
|
||||
local resolved capture_root workspace_path
|
||||
resolved=$(resolve_requested_path "$path")
|
||||
capture_root=$(resolve_requested_path "$default_output")
|
||||
workspace_path=$(resolve_requested_path "$workspace_root")
|
||||
case "$resolved" in
|
||||
"$capture_root"|"${capture_root}/"*|"$workspace_path"|"${workspace_path}/"*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ ${1-} != "capture" ]]; then
|
||||
printf 'usage: slopcap capture --interface <iface> [--filter <expr>] [--output <path>] [--stdout]\n' >&2
|
||||
@@ -633,6 +918,12 @@ done
|
||||
if [[ -z $output && $stdout_mode -eq 0 ]]; then
|
||||
output="$default_output/capture-$(date +%s).pcap"
|
||||
fi
|
||||
if [[ -n $output ]] && ! validate_output_path "$output"; then
|
||||
printf 'slopcap: output path must stay within %s or %s\n' "$default_output" "$workspace_root" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
ensure_helper_ready
|
||||
|
||||
request_dir=$(mktemp -d "$queue_dir/request.XXXXXX.req")
|
||||
trap 'rm -rf "$request_dir"' EXIT INT TERM HUP
|
||||
@@ -674,6 +965,19 @@ EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
caps=${SLOPTRAP_ACTIVE_CAPABILITIES:-}
|
||||
|
||||
has_capability() {
|
||||
local needle=$1
|
||||
local token
|
||||
for token in $caps; do
|
||||
if [[ $token == "$needle" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
printf 'usage: sloppodman <pull|build|tag|run|ps|logs|stop|rm|inspect> ...\n' >&2
|
||||
exit 2
|
||||
@@ -691,6 +995,11 @@ case "$subcommand" in
|
||||
;;
|
||||
esac
|
||||
|
||||
has_capability "nested-podman" || {
|
||||
printf 'sloppodman: capability nested-podman is not active\n' >&2
|
||||
exit 126
|
||||
}
|
||||
|
||||
workspace_root=${SLOPTRAP_WORKDIR:-/workspace}
|
||||
podman_root=${SLOPTRAP_INNER_PODMAN_ROOT:-/codex/capabilities/podman/storage}
|
||||
podman_runroot=${SLOPTRAP_INNER_PODMAN_RUNROOT:-/codex/capabilities/podman/run}
|
||||
@@ -721,6 +1030,63 @@ validate_workspace_path() {
|
||||
esac
|
||||
}
|
||||
|
||||
reject_flag() {
|
||||
local flag=$1
|
||||
printf 'sloppodman: %s is not permitted\n' "$flag" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
validate_volume_spec() {
|
||||
local spec=$1
|
||||
local source
|
||||
if [[ $spec != *:* ]]; then
|
||||
return 0
|
||||
fi
|
||||
source=${spec%%:*}
|
||||
case "$source" in
|
||||
"" )
|
||||
return 0
|
||||
;;
|
||||
.|..|/*|./*|../*|*/*)
|
||||
validate_workspace_path "$source"
|
||||
;;
|
||||
* )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_mount_spec() {
|
||||
local spec=$1
|
||||
local type=""
|
||||
local source=""
|
||||
local part
|
||||
IFS=',' read -r -a mount_parts <<< "$spec"
|
||||
for part in "${mount_parts[@]}"; do
|
||||
case "$part" in
|
||||
type=*)
|
||||
type=${part#type=}
|
||||
;;
|
||||
source=*|src=*)
|
||||
source=${part#*=}
|
||||
;;
|
||||
esac
|
||||
done
|
||||
case "$type" in
|
||||
volume|tmpfs)
|
||||
return 0
|
||||
;;
|
||||
bind)
|
||||
[[ -n $source ]] || reject_flag "--mount"
|
||||
validate_workspace_path "$source"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
reject_flag "--mount"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ $subcommand == "build" ]]; then
|
||||
args=("$@")
|
||||
context=""
|
||||
@@ -733,6 +1099,9 @@ if [[ $subcommand == "build" ]]; then
|
||||
(( idx < ${#args[@]} )) || { printf 'sloppodman: %s requires a path\n' "$arg" >&2; exit 2; }
|
||||
validate_workspace_path "${args[$idx]}"
|
||||
;;
|
||||
--file=*)
|
||||
validate_workspace_path "${arg#*=}"
|
||||
;;
|
||||
--network)
|
||||
((idx+=1))
|
||||
(( idx < ${#args[@]} )) || { printf 'sloppodman: --network requires a value\n' >&2; exit 2; }
|
||||
@@ -741,6 +1110,15 @@ if [[ $subcommand == "build" ]]; then
|
||||
exit 2
|
||||
fi
|
||||
;;
|
||||
--network=*)
|
||||
if [[ ${arg#*=} == "host" && ${SLOPTRAP_INNER_PODMAN_HOST_NETWORK:-0} != 1 ]]; then
|
||||
printf 'sloppodman: host networking is not available in this session\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
;;
|
||||
-v|--volume|--volume=*|--mount|--mount=*|--security-opt|--security-opt=*|--cap-add|--cap-add=*|--cap-drop|--cap-drop=*|--device|--device=*|--privileged|--privileged=*|--rootfs|--rootfs=*)
|
||||
reject_flag "${arg%%=*}"
|
||||
;;
|
||||
esac
|
||||
((idx+=1))
|
||||
done
|
||||
@@ -755,14 +1133,49 @@ if [[ $subcommand == "run" ]]; then
|
||||
idx=0
|
||||
while (( idx < ${#args[@]} )); do
|
||||
arg=${args[$idx]}
|
||||
if [[ $arg == "--network" ]]; then
|
||||
((idx+=1))
|
||||
(( idx < ${#args[@]} )) || { printf 'sloppodman: --network requires a value\n' >&2; exit 2; }
|
||||
if [[ ${args[$idx]} == "host" && ${SLOPTRAP_INNER_PODMAN_HOST_NETWORK:-0} != 1 ]]; then
|
||||
printf 'sloppodman: host networking is not available in this session\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
case "$arg" in
|
||||
--)
|
||||
break
|
||||
;;
|
||||
--network)
|
||||
((idx+=1))
|
||||
(( idx < ${#args[@]} )) || { printf 'sloppodman: --network requires a value\n' >&2; exit 2; }
|
||||
if [[ ${args[$idx]} == "host" && ${SLOPTRAP_INNER_PODMAN_HOST_NETWORK:-0} != 1 ]]; then
|
||||
printf 'sloppodman: host networking is not available in this session\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
;;
|
||||
--network=*)
|
||||
if [[ ${arg#*=} == "host" && ${SLOPTRAP_INNER_PODMAN_HOST_NETWORK:-0} != 1 ]]; then
|
||||
printf 'sloppodman: host networking is not available in this session\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
;;
|
||||
-v|--volume)
|
||||
((idx+=1))
|
||||
(( idx < ${#args[@]} )) || { printf 'sloppodman: %s requires a value\n' "$arg" >&2; exit 2; }
|
||||
validate_volume_spec "${args[$idx]}"
|
||||
;;
|
||||
--volume=*)
|
||||
validate_volume_spec "${arg#*=}"
|
||||
;;
|
||||
--mount)
|
||||
((idx+=1))
|
||||
(( idx < ${#args[@]} )) || { printf 'sloppodman: --mount requires a value\n' >&2; exit 2; }
|
||||
validate_mount_spec "${args[$idx]}"
|
||||
;;
|
||||
--mount=*)
|
||||
validate_mount_spec "${arg#*=}"
|
||||
;;
|
||||
--privileged|--privileged=*|--cap-add|--cap-add=*|--cap-drop|--cap-drop=*|--device|--device=*|--security-opt|--security-opt=*|--rootfs|--rootfs=*|--pid|--pid=*|--ipc|--ipc=*|--uts|--uts=*|--userns|--userns=*|--cgroupns|--cgroupns=*)
|
||||
reject_flag "${arg%%=*}"
|
||||
;;
|
||||
-*)
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
((idx+=1))
|
||||
done
|
||||
fi
|
||||
@@ -880,6 +1293,11 @@ ensure_capability_state_paths() {
|
||||
ensure_codex_directory "$CAPABILITY_TRUST_ROOT_HOST" "sloptrap capability trust root"
|
||||
ensure_codex_directory "$(dirname "$CAPABILITY_BUILD_STAMP_HOST")" "sloptrap capability build stamp root"
|
||||
ensure_codex_directory "$CAPABILITY_STATE_HOST" "project capability state"
|
||||
if capability_list_contains "$REQUESTED_CAPABILITIES" "nested-podman"; then
|
||||
ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-storage" "nested podman storage state"
|
||||
ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-run" "nested podman runroot state"
|
||||
ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-runtime" "nested podman runtime state"
|
||||
fi
|
||||
}
|
||||
|
||||
capability_trust_matches_current() {
|
||||
@@ -1189,7 +1607,7 @@ validate_package_list() {
|
||||
[[ -z $raw ]] && return 0
|
||||
local token
|
||||
for token in $raw; do
|
||||
if [[ ! $token =~ ^[A-Za-z0-9+.-]+$ ]]; then
|
||||
if [[ ! $token =~ ^[A-Za-z0-9][A-Za-z0-9+.-]*$ ]]; then
|
||||
error "$source: invalid package name '$token' in '$key'"
|
||||
fi
|
||||
done
|
||||
@@ -1465,16 +1883,7 @@ print_manifest_summary() {
|
||||
}
|
||||
|
||||
build_runtime_context_prompt() {
|
||||
local manifest_present prompt manifest_capabilities trusted enabled network_mode
|
||||
manifest_present="false"
|
||||
if [[ -f $MANIFEST_PATH ]]; then
|
||||
manifest_present="true"
|
||||
fi
|
||||
manifest_capabilities=${REQUESTED_CAPABILITIES:-none}
|
||||
trusted="none"
|
||||
if [[ -n $REQUESTED_CAPABILITIES ]] && capability_trust_matches_current; then
|
||||
trusted=$REQUESTED_CAPABILITIES
|
||||
fi
|
||||
local prompt enabled network_mode
|
||||
enabled=${ENABLED_CAPABILITIES:-none}
|
||||
network_mode="isolated"
|
||||
if [[ $SLOPTRAP_NETWORK_NAME == "host" ]]; then
|
||||
@@ -1484,28 +1893,11 @@ build_runtime_context_prompt() {
|
||||
You are running inside sloptrap, which confines Codex inside a container.
|
||||
This startup note describes the sloptrap runtime only; it does not replace higher-priority instructions from AGENTS.md or the system.
|
||||
|
||||
Container layout:
|
||||
- /workspace is the project mount.
|
||||
- /codex is persistent Codex state for this project.
|
||||
- The project manifest path is /workspace/.sloptrap and it may be absent.
|
||||
|
||||
Manifest key meanings:
|
||||
- name: labels the sloptrap project/image/container names.
|
||||
- packages_extra: Debian packages added when the image was built.
|
||||
- capabilities: privileged features requested by the manifest; only capabilities enabled for this run are currently usable.
|
||||
- allow_host_network: enables host networking when true; otherwise networking is isolated.
|
||||
|
||||
Current resolved sloptrap state:
|
||||
- manifest_present=$manifest_present
|
||||
- project_name=$PROJECT_NAME
|
||||
- packages_extra=${PACKAGES_EXTRA:-none}
|
||||
- manifest_capabilities=$manifest_capabilities
|
||||
- trusted_capabilities=$trusted
|
||||
- enabled_capabilities=$enabled
|
||||
- network_mode=$network_mode
|
||||
- runtime_flags=$CODEX_ARGS_DISPLAY
|
||||
|
||||
If you need exact project configuration, inspect /workspace/.sloptrap directly.
|
||||
- name=$PROJECT_NAME (project/image/container label)
|
||||
- packages_extra=${PACKAGES_EXTRA:-none} (Debian packages added at build time)
|
||||
- enabled_capabilities=$enabled (privileged features usable in this run)
|
||||
- network_mode=$network_mode (host when host networking is enabled; otherwise isolated)
|
||||
EOF
|
||||
)
|
||||
printf '%s' "$prompt"
|
||||
@@ -1785,7 +2177,7 @@ prepare_container_runtime() {
|
||||
SLOPTRAP_PACKAGES_CAPABILITY+=" tcpdump"
|
||||
fi
|
||||
if capability_list_contains "$REQUESTED_CAPABILITIES" "nested-podman"; then
|
||||
SLOPTRAP_PACKAGES_CAPABILITY+=" podman fuse-overlayfs slirp4netns"
|
||||
SLOPTRAP_PACKAGES_CAPABILITY+=" podman uidmap fuse-overlayfs slirp4netns"
|
||||
fi
|
||||
SLOPTRAP_PACKAGES_CAPABILITY=$(normalize_package_list "$SLOPTRAP_PACKAGES_CAPABILITY")
|
||||
local default_codex_archive
|
||||
@@ -1877,6 +2269,15 @@ prepare_container_runtime() {
|
||||
if capability_list_contains "$ENABLED_CAPABILITIES" "nested-podman"; then
|
||||
capability_opts+=(--device /dev/fuse)
|
||||
fi
|
||||
if $SLOPTRAP_RUN_AS_ROOT; then
|
||||
capability_opts+=(
|
||||
--cap-add SETUID
|
||||
--cap-add SETGID
|
||||
--cap-add CHOWN
|
||||
--cap-add DAC_OVERRIDE
|
||||
--cap-add FOWNER
|
||||
)
|
||||
fi
|
||||
|
||||
local rootfs_flag=()
|
||||
case "${SLOPTRAP_ROOTFS_READONLY,,}" in
|
||||
@@ -1911,7 +2312,7 @@ prepare_container_runtime() {
|
||||
-e "XDG_STATE_HOME=$SLOPTRAP_CODEX_HOME_CONT/state"
|
||||
-e "CODEX_HOME=$SLOPTRAP_CODEX_HOME_CONT"
|
||||
-e "SLOPTRAP_WORKDIR=$SLOPTRAP_WORKDIR"
|
||||
-e "SLOPTRAP_HELPER_DIR=/run/sloptrap-helper"
|
||||
-e "SLOPTRAP_HELPER_DIR=/tmp/sloptrap-helper"
|
||||
-e "SLOPTRAP_ACTIVE_CAPABILITIES=$ENABLED_CAPABILITIES"
|
||||
-e "SLOPTRAP_CAPTURE_DIR=$SLOPTRAP_CODEX_HOME_CONT/state/captures"
|
||||
-e "SLOPTRAP_AUDIT_LOG=$SLOPTRAP_CODEX_HOME_CONT/state/capabilities.log"
|
||||
@@ -1926,12 +2327,19 @@ prepare_container_runtime() {
|
||||
local uid gid
|
||||
uid=$(id -u)
|
||||
gid=$(id -g)
|
||||
env_args+=(
|
||||
-e "SLOPTRAP_HOST_UID=$uid"
|
||||
-e "SLOPTRAP_HOST_GID=$gid"
|
||||
)
|
||||
local -a user_opts=("--user" "$uid:$gid")
|
||||
if [[ $CONTAINER_ENGINE == "podman" ]]; then
|
||||
user_opts=(--userns="keep-id:uid=$uid,gid=$gid" "${user_opts[@]}")
|
||||
fi
|
||||
if $SLOPTRAP_RUN_AS_ROOT; then
|
||||
user_opts=()
|
||||
if [[ $CONTAINER_ENGINE == "podman" ]]; then
|
||||
user_opts=(--userns="keep-id:uid=$uid,gid=$gid")
|
||||
fi
|
||||
fi
|
||||
|
||||
CONTAINER_SHARED_OPTS=(
|
||||
|
||||
@@ -211,6 +211,33 @@ teardown_stub_env() {
|
||||
rm -f "${STUB_LOG:-}"
|
||||
}
|
||||
|
||||
extract_embedded_helper() {
|
||||
local helper=$1
|
||||
local output=$2
|
||||
if ! awk -v helper="$helper" '
|
||||
$0 ~ "^[[:space:]]*" helper "\\)$" { state=1; next }
|
||||
state == 1 && /cat <<'\''EOF'\''$/ { state=2; next }
|
||||
state == 2 && /^EOF$/ { exit }
|
||||
state == 2 { print }
|
||||
' "$SLOPTRAP_BIN" >"$output"; then
|
||||
return 1
|
||||
fi
|
||||
chmod +x "$output"
|
||||
}
|
||||
|
||||
wait_for_path() {
|
||||
local path=$1
|
||||
local attempts=${2:-100}
|
||||
while (( attempts > 0 )); do
|
||||
if [[ -e $path ]]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
((attempts-=1))
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
record_failure() {
|
||||
failures+=("$1")
|
||||
}
|
||||
@@ -302,6 +329,22 @@ run_secret_mask() {
|
||||
teardown_stub_env
|
||||
}
|
||||
|
||||
run_git_ignore_mask() {
|
||||
local scenario_dir="$ROOT_DIR"
|
||||
printf '==> git_ignore_mask\n'
|
||||
setup_stub_env
|
||||
if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \
|
||||
"$SLOPTRAP_BIN" --trust-capabilities "$scenario_dir" </dev/null >/dev/null 2>&1; then
|
||||
record_failure "git_ignore_mask: sloptrap exited non-zero"
|
||||
teardown_stub_env
|
||||
return
|
||||
fi
|
||||
if ! grep -q -- "--mount type=tmpfs,target=/workspace/.git" "$STUB_LOG"; then
|
||||
record_failure "git_ignore_mask: .git was not masked with tmpfs"
|
||||
fi
|
||||
teardown_stub_env
|
||||
}
|
||||
|
||||
run_resume_target() {
|
||||
local scenario_dir="$TEST_ROOT/resume_target"
|
||||
printf '==> resume_target\n'
|
||||
@@ -335,10 +378,9 @@ run_runtime_context_prompt() {
|
||||
if [[ -z $run_line || $run_line != *"You are running inside sloptrap"* ]]; then
|
||||
record_failure "runtime_context_prompt: startup prompt missing from fresh run"
|
||||
fi
|
||||
if ! grep -q -- "manifest_present=true" "$STUB_LOG" \
|
||||
|| ! grep -q -- "manifest_capabilities=apt-install nested-podman packet-capture" "$STUB_LOG" \
|
||||
|| ! grep -q -- "trusted_capabilities=apt-install nested-podman packet-capture" "$STUB_LOG" \
|
||||
|| ! grep -q -- "enabled_capabilities=apt-install nested-podman packet-capture" "$STUB_LOG"; then
|
||||
if ! grep -q -- "name=capability-repo" "$STUB_LOG" \
|
||||
|| ! grep -q -- "enabled_capabilities=apt-install nested-podman packet-capture" "$STUB_LOG" \
|
||||
|| ! grep -q -- "network_mode=host" "$STUB_LOG"; then
|
||||
record_failure "runtime_context_prompt: runtime summary missing manifest or capability state"
|
||||
fi
|
||||
if [[ -n $login_line && $login_line == *"You are running inside sloptrap"* ]]; then
|
||||
@@ -690,7 +732,7 @@ run_capability_profiles() {
|
||||
teardown_stub_env
|
||||
return
|
||||
fi
|
||||
if ! grep -q -- "CAPABILITY_PACKAGES=tcpdump podman fuse-overlayfs slirp4netns" "$STUB_LOG"; then
|
||||
if ! grep -q -- "CAPABILITY_PACKAGES=tcpdump podman uidmap fuse-overlayfs slirp4netns" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: build arg for capability packages missing"
|
||||
fi
|
||||
if ! grep -q -- "--cap-add NET_RAW" "$STUB_LOG"; then
|
||||
@@ -702,21 +744,279 @@ run_capability_profiles() {
|
||||
if ! grep -q -- "--device /dev/fuse" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: /dev/fuse device missing"
|
||||
fi
|
||||
if ! grep -q -- "--cap-add SETUID" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: SETUID capability missing"
|
||||
fi
|
||||
if ! grep -q -- "--cap-add SETGID" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: SETGID capability missing"
|
||||
fi
|
||||
if ! grep -q -- "--cap-add CHOWN" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: CHOWN capability missing"
|
||||
fi
|
||||
if ! grep -q -- "--cap-add DAC_OVERRIDE" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: DAC_OVERRIDE capability missing"
|
||||
fi
|
||||
if ! grep -q -- "--cap-add FOWNER" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: FOWNER capability missing"
|
||||
fi
|
||||
if grep -q -- "--read-only" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: apt profile should disable read-only rootfs"
|
||||
fi
|
||||
if grep -q -- "--user " "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: capability-enabled run should not force --user"
|
||||
fi
|
||||
if ! grep -q -- "--userns=keep-id:uid=$(id -u),gid=$(id -g)" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: podman keep-id user namespace missing"
|
||||
fi
|
||||
if ! grep -q -- "SLOPTRAP_ACTIVE_CAPABILITIES=apt-install nested-podman packet-capture" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: active capability environment missing"
|
||||
fi
|
||||
if ! grep -q -- "SLOPTRAP_HOST_UID=$(id -u)" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: host uid environment missing"
|
||||
fi
|
||||
if ! grep -q -- "SLOPTRAP_HOST_GID=$(id -g)" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: host gid environment missing"
|
||||
fi
|
||||
if ! grep -q -- "SLOPTRAP_INNER_PODMAN_HOST_NETWORK=1" "$STUB_LOG"; then
|
||||
record_failure "capability_profiles: inner podman host-network mirror flag missing"
|
||||
fi
|
||||
local state_root capability_dir
|
||||
state_root="$STUB_HOME/.codex/sloptrap/state"
|
||||
capability_dir=$(find "$state_root" -mindepth 2 -maxdepth 2 -type d -name capabilities | head -n 1 || true)
|
||||
if [[ -z $capability_dir ]]; then
|
||||
record_failure "capability_profiles: project capability state directory missing"
|
||||
else
|
||||
if [[ ! -d $capability_dir/podman-storage ]]; then
|
||||
record_failure "capability_profiles: nested podman storage state missing"
|
||||
fi
|
||||
if [[ ! -d $capability_dir/podman-run ]]; then
|
||||
record_failure "capability_profiles: nested podman runroot state missing"
|
||||
fi
|
||||
if [[ ! -d $capability_dir/podman-runtime ]]; then
|
||||
record_failure "capability_profiles: nested podman runtime state missing"
|
||||
fi
|
||||
fi
|
||||
teardown_stub_env
|
||||
}
|
||||
|
||||
run_embedded_capability_helpers() {
|
||||
printf '==> embedded_capability_helpers\n'
|
||||
local temp_root helper_bin helper_dir workspace_dir capture_dir tool_log helper_pid
|
||||
local inner_podman_root inner_podman_runroot inner_runtime_dir
|
||||
temp_root=$(mktemp -d)
|
||||
helper_bin="$temp_root/bin"
|
||||
helper_dir="$temp_root/helper"
|
||||
workspace_dir="$temp_root/workspace"
|
||||
capture_dir="$temp_root/captures"
|
||||
tool_log="$temp_root/tool.log"
|
||||
inner_podman_root="$temp_root/podman-storage"
|
||||
inner_podman_runroot="$temp_root/podman-run"
|
||||
inner_runtime_dir="$temp_root/podman-runtime"
|
||||
helper_pid=""
|
||||
mkdir -p "$helper_bin" "$helper_dir/queue" "$workspace_dir/data" "$capture_dir" \
|
||||
"$inner_podman_root" "$inner_podman_runroot" "$inner_runtime_dir"
|
||||
: >"$tool_log"
|
||||
|
||||
if ! extract_embedded_helper "sloptrap-entrypoint" "$helper_bin/sloptrap-entrypoint" \
|
||||
|| ! extract_embedded_helper "sloptrap-helperd" "$helper_bin/sloptrap-helperd" \
|
||||
|| ! extract_embedded_helper "slop-apt" "$helper_bin/slop-apt" \
|
||||
|| ! extract_embedded_helper "slopcap" "$helper_bin/slopcap" \
|
||||
|| ! extract_embedded_helper "sloppodman" "$helper_bin/sloppodman"; then
|
||||
record_failure "embedded_capability_helpers: failed to extract embedded helper scripts"
|
||||
rm -rf "$temp_root"
|
||||
return
|
||||
fi
|
||||
|
||||
cat >"$helper_bin/podman" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'podman %s\n' "$*" >>"$TEST_TOOL_LOG"
|
||||
exit 0
|
||||
EOF
|
||||
cat >"$helper_bin/apt-get" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'apt-get %s\n' "$*" >>"$TEST_TOOL_LOG"
|
||||
exit 0
|
||||
EOF
|
||||
cat >"$helper_bin/tcpdump" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'tcpdump %s\n' "$*" >>"$TEST_TOOL_LOG"
|
||||
output=""
|
||||
prev=""
|
||||
for arg in "$@"; do
|
||||
if [[ $prev == "-w" ]]; then
|
||||
output=$arg
|
||||
break
|
||||
fi
|
||||
prev=$arg
|
||||
done
|
||||
if [[ -n $output ]]; then
|
||||
mkdir -p "$(dirname "$output")"
|
||||
: >"$output"
|
||||
fi
|
||||
exit 0
|
||||
EOF
|
||||
cat >"$helper_bin/setpriv" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--reuid|--regid)
|
||||
shift 2
|
||||
;;
|
||||
--clear-groups)
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
exec "$@"
|
||||
EOF
|
||||
chmod +x "$helper_bin/podman" "$helper_bin/apt-get" "$helper_bin/tcpdump" "$helper_bin/setpriv"
|
||||
|
||||
if ! grep -q "chmod 711 \"\\\$helper_dir\"" "$helper_bin/sloptrap-entrypoint" \
|
||||
|| ! grep -q "chown \"\\\$target_uid:\\\$target_gid\" \"\\\$queue_dir\"" "$helper_bin/sloptrap-entrypoint"; then
|
||||
record_failure "embedded_capability_helpers: entrypoint did not expose helper queue to the dropped user"
|
||||
fi
|
||||
|
||||
local autostart_helper_dir
|
||||
autostart_helper_dir="$temp_root/helper-autostart"
|
||||
if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$autostart_helper_dir" \
|
||||
SLOPTRAP_ACTIVE_CAPABILITIES="apt-install packet-capture" \
|
||||
SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
SLOPTRAP_AUDIT_LOG="$temp_root/autostart-audit.log" \
|
||||
SLOPTRAP_HOST_UID="$(id -u)" SLOPTRAP_HOST_GID="$(id -g)" \
|
||||
"$helper_bin/slop-apt" install jq >/dev/null 2>&1; then
|
||||
record_failure "embedded_capability_helpers: slop-apt did not self-bootstrap the helper daemon"
|
||||
fi
|
||||
if [[ ! -r $autostart_helper_dir/helperd.pid ]]; then
|
||||
record_failure "embedded_capability_helpers: helper self-bootstrap did not create a pid file"
|
||||
else
|
||||
kill "$(cat "$autostart_helper_dir/helperd.pid")" >/dev/null 2>&1 || true
|
||||
wait "$(cat "$autostart_helper_dir/helperd.pid")" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
local missing_cap_status=0
|
||||
if TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_ACTIVE_CAPABILITIES="" \
|
||||
SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
SLOPTRAP_INNER_PODMAN_ROOT="$inner_podman_root" \
|
||||
SLOPTRAP_INNER_PODMAN_RUNROOT="$inner_podman_runroot" \
|
||||
XDG_RUNTIME_DIR="$inner_runtime_dir" \
|
||||
"$helper_bin/sloppodman" ps >/dev/null 2>&1; then
|
||||
record_failure "embedded_capability_helpers: sloppodman should reject runs without nested-podman"
|
||||
else
|
||||
missing_cap_status=$?
|
||||
fi
|
||||
if [[ $missing_cap_status -ne 126 ]]; then
|
||||
record_failure "embedded_capability_helpers: sloppodman returned the wrong status when capability was absent"
|
||||
fi
|
||||
|
||||
if TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_ACTIVE_CAPABILITIES="nested-podman" \
|
||||
SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
SLOPTRAP_INNER_PODMAN_ROOT="$inner_podman_root" \
|
||||
SLOPTRAP_INNER_PODMAN_RUNROOT="$inner_podman_runroot" \
|
||||
XDG_RUNTIME_DIR="$inner_runtime_dir" \
|
||||
"$helper_bin/sloppodman" run --privileged example/image >/dev/null 2>&1; then
|
||||
record_failure "embedded_capability_helpers: sloppodman allowed --privileged"
|
||||
fi
|
||||
|
||||
if TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_ACTIVE_CAPABILITIES="nested-podman" \
|
||||
SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
SLOPTRAP_INNER_PODMAN_ROOT="$inner_podman_root" \
|
||||
SLOPTRAP_INNER_PODMAN_RUNROOT="$inner_podman_runroot" \
|
||||
XDG_RUNTIME_DIR="$inner_runtime_dir" \
|
||||
"$helper_bin/sloppodman" run -v /tmp:/host example/image >/dev/null 2>&1; then
|
||||
record_failure "embedded_capability_helpers: sloppodman allowed an out-of-workspace bind mount"
|
||||
fi
|
||||
|
||||
if ! (
|
||||
cd "$workspace_dir" && TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" \
|
||||
SLOPTRAP_ACTIVE_CAPABILITIES="nested-podman" SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
SLOPTRAP_INNER_PODMAN_ROOT="$inner_podman_root" \
|
||||
SLOPTRAP_INNER_PODMAN_RUNROOT="$inner_podman_runroot" \
|
||||
XDG_RUNTIME_DIR="$inner_runtime_dir" \
|
||||
"$helper_bin/sloppodman" run -v ./data:/data example/image true >/dev/null 2>&1
|
||||
); then
|
||||
record_failure "embedded_capability_helpers: sloppodman rejected a workspace-local bind mount"
|
||||
fi
|
||||
if ! grep -q -- 'podman --root ' "$tool_log" || ! grep -q -- '-v ./data:/data' "$tool_log"; then
|
||||
record_failure "embedded_capability_helpers: sloppodman did not invoke podman with the validated run arguments"
|
||||
fi
|
||||
|
||||
TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \
|
||||
SLOPTRAP_ACTIVE_CAPABILITIES="apt-install packet-capture" \
|
||||
SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
SLOPTRAP_AUDIT_LOG="$temp_root/audit.log" "$helper_bin/sloptrap-helperd" >/dev/null 2>&1 &
|
||||
helper_pid=$!
|
||||
|
||||
if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \
|
||||
"$helper_bin/slop-apt" install jq >/dev/null 2>&1; then
|
||||
record_failure "embedded_capability_helpers: slop-apt failed against the embedded helper daemon"
|
||||
fi
|
||||
if ! grep -q -- 'apt-get install -y --no-install-recommends jq' "$tool_log"; then
|
||||
record_failure "embedded_capability_helpers: slop-apt did not reach apt-get install"
|
||||
fi
|
||||
|
||||
local bad_apt_request
|
||||
bad_apt_request=$(mktemp -d "$helper_dir/queue/request.XXXXXX.req")
|
||||
printf 'apt-install\n' >"$bad_apt_request/op"
|
||||
printf '%s\n' '--allow-unauthenticated' >"$bad_apt_request/packages"
|
||||
if ! wait_for_path "$bad_apt_request/status"; then
|
||||
record_failure "embedded_capability_helpers: helper daemon did not answer the invalid apt request"
|
||||
elif [[ $(<"$bad_apt_request/status") != "2" ]]; then
|
||||
record_failure "embedded_capability_helpers: invalid apt request returned the wrong status"
|
||||
fi
|
||||
if [[ -s "$bad_apt_request/stderr" ]] && ! grep -q -- 'invalid package name' "$bad_apt_request/stderr"; then
|
||||
record_failure "embedded_capability_helpers: invalid apt request did not explain the rejection"
|
||||
fi
|
||||
|
||||
if TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \
|
||||
SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
"$helper_bin/slopcap" capture --interface eth0 --output /tmp/escape.pcap >/dev/null 2>&1; then
|
||||
record_failure "embedded_capability_helpers: slopcap accepted an out-of-bounds output path"
|
||||
fi
|
||||
|
||||
if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \
|
||||
SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \
|
||||
"$helper_bin/slopcap" capture --interface eth0 --filter 'tcp port 80' \
|
||||
--output "$workspace_dir/capture.pcap" >/dev/null 2>&1; then
|
||||
record_failure "embedded_capability_helpers: slopcap failed for a workspace-local capture file"
|
||||
fi
|
||||
if ! grep -q -- "tcpdump -i eth0 -w $workspace_dir/capture.pcap -- tcp port 80" "$tool_log"; then
|
||||
record_failure "embedded_capability_helpers: slopcap did not invoke tcpdump with the expected guarded arguments"
|
||||
fi
|
||||
|
||||
local bad_capture_request
|
||||
bad_capture_request=$(mktemp -d "$helper_dir/queue/request.XXXXXX.req")
|
||||
printf 'packet-capture\n' >"$bad_capture_request/op"
|
||||
printf 'eth0\n' >"$bad_capture_request/interface"
|
||||
printf '\n' >"$bad_capture_request/filter"
|
||||
printf '/tmp/escape.pcap\n' >"$bad_capture_request/output"
|
||||
printf '0\n' >"$bad_capture_request/stdout_mode"
|
||||
if ! wait_for_path "$bad_capture_request/status"; then
|
||||
record_failure "embedded_capability_helpers: helper daemon did not answer the invalid capture request"
|
||||
elif [[ $(<"$bad_capture_request/status") != "2" ]]; then
|
||||
record_failure "embedded_capability_helpers: invalid capture request returned the wrong status"
|
||||
fi
|
||||
if [[ -s "$bad_capture_request/stderr" ]] && ! grep -q -- 'output path must stay within' "$bad_capture_request/stderr"; then
|
||||
record_failure "embedded_capability_helpers: invalid capture request did not explain the rejection"
|
||||
fi
|
||||
|
||||
if [[ -n $helper_pid ]]; then
|
||||
kill "$helper_pid" >/dev/null 2>&1 || true
|
||||
wait "$helper_pid" >/dev/null 2>&1 || true
|
||||
fi
|
||||
rm -rf "$temp_root"
|
||||
}
|
||||
|
||||
run_make_install_single_file() {
|
||||
local scenario_dir="$TEST_ROOT/resume_target"
|
||||
printf '==> make_install_single_file\n'
|
||||
@@ -768,6 +1068,7 @@ run_symlink_escape
|
||||
run_manifest_injection
|
||||
run_helper_symlink
|
||||
run_secret_mask
|
||||
run_git_ignore_mask
|
||||
run_resume_target
|
||||
run_runtime_context_prompt
|
||||
run_sh_reexec
|
||||
@@ -791,6 +1092,7 @@ run_wizard_existing_defaults
|
||||
run_wizard_build_trigger
|
||||
run_capability_trust_required
|
||||
run_capability_profiles
|
||||
run_embedded_capability_helpers
|
||||
run_make_install_single_file
|
||||
|
||||
if [[ ${#failures[@]} -gt 0 ]]; then
|
||||
|
||||
Reference in New Issue
Block a user