buildPkillShim function
The pkill PATH shim: expands the match with the REAL pgrep (the
same selection engine and flags), filters the protected pids, the
invoking shell (PPID) and the shim itself, then signals the rest with
the requested signal (default SIGTERM). Selection shapes the shim
models: signal forms (-9, -SIGTERM, --signal[=]), the
value-taking selection flags in split form (-u <uid>, -t <tty>,
…) and glued form (-urot), and plain selection flags (-f, -x,
…). Everything else — output modes (-c, -v, -l, -a, --count,
any other long option), a signal spelled after the pattern, extra
operands, or a selection pgrep rejects — execs the real pkill
(honest behavior over silent guessing): outside the shim the harness
chain is NOT protected.
Implementation
String buildPkillShim({required String realPkill, required String realPgrep}) =>
r'''#!/bin/sh
# fa bash-guard shim for pkill (gh-1763): never signals the harness or its
# ancestor chain, the invoking shell, or itself.
set -u
FA_REAL_PKILL='__FA_REAL_PKILL__'
FA_REAL_PGREP='__FA_REAL_PGREP__'
sig=''
sel=''
fa_dd=0
# Flags that would corrupt the victim set never enter the guarded path —
# the real pkill decides:
# - output modes (c = count prints a number the victim loop would read as
# a pid, v = negated match, l/a = list modes the real pkill rejects with
# a usage error — their pgrep output is "pid name" rows, not a pid list);
# - any other long option (only --signal/--signal=<sig> is modeled).
for a in "$@"; do
case "$a" in
--|--signal|--signal=*) continue ;;
--*) exec "$FA_REAL_PKILL" "$@" ;;
-[a-zA-Z]*)
fa_body="${a#-}"
case "$fa_body" in
[0-9]*|[Ss][Ii][Gg]*|[A-Z]*) continue ;;
esac
fa_rest="$fa_body"
while [ -n "$fa_rest" ]; do
fa_c="${fa_rest%"${fa_rest#?}"}"
case "$fa_c" in
[cval]) exec "$FA_REAL_PKILL" "$@" ;;
esac
fa_rest="${fa_rest#?}"
done
;;
esac
done
while [ $# -gt 0 ]; do
case "$1" in
--signal)
if [ "$#" -ge 2 ]; then sig="$2"; shift 2
else exec "$FA_REAL_PKILL" "$@"; fi
;;
--signal=*) sig="${1#--signal=}"; shift ;;
--) fa_dd=1; shift; break ;;
-[0-9]*) sig="$1"; shift ;;
-[Ss][Ii][Gg][A-Za-z]*|-[A-Z][A-Z]*) sig="$1"; shift ;;
# Value-taking selection flags (procps: -u -U -g -s -t -P -G -r -O -q
# -F): the value may ride the next argv item (split form, e.g.
# `pkill -u "$(id -u)" -f <pat>`). Consume both into the selection so
# the guarded path still runs — execing the real, unshimed pkill here
# would leave the harness unprotected (the gh-1763 crash shape). The
# glued forms (-urot) ride the generic case below.
-u|-U|-g|-s|-t|-P|-G|-r|-O|-q|-F)
if [ "$#" -ge 2 ]; then
sel="$sel $1 $2"
shift 2
else
exec "$FA_REAL_PKILL" "$@"
fi
;;
-*) sel="$sel $1"; shift ;;
*) break ;;
esac
done
# Exactly one operand (the pattern) must remain; anything else — unknown
# flags interleaved with it, extra operands — is the real pkill's call.
if [ "$#" -ne 1 ]; then
if [ "$fa_dd" = 1 ]; then exec "$FA_REAL_PKILL" -- "$@"; fi
exec "$FA_REAL_PKILL" "$@"
fi
# The selection flags ride along: pgrep shares pkill's selection engine.
pids=$("$FA_REAL_PGREP" $sel "$@" 2>/dev/null)
rc=$?
if [ "$rc" -ge 2 ]; then
# pgrep rejected the selection (a flag it does not share): the real
# pkill decides, semantics stay honest. A consumed `--` is re-emitted
# so the surviving operands stay operands (`pkill -- -<pat>`).
if [ "$fa_dd" = 1 ]; then exec "$FA_REAL_PKILL" -- "$@"; fi
exec "$FA_REAL_PKILL" "$@"
fi
[ "$rc" -eq 0 ] || exit 1
# Output modes never reach this pgrep call (they exec the real pkill
# above), so pgrep prints bare pids; the cut is belt-and-braces — list
# rows like "pid name" would turn the name column into a phantom kill
# target.
pids=$(printf '%s\n' "$pids" | cut -d' ' -f1)
# --signal/--signal= store the NAME without the leading dash; normalize
# so `kill "$sig" <pid>` works for TERM, KILL and 9 alike.
case "$sig" in -*) ;; ?*) sig="-$sig" ;; esac
self=$$
parent="${PPID:-}"
out=0
for p in $pids; do
case " ${FA_PROTECTED_PIDS:-} " in *" $p "*) continue ;; esac
if [ "$p" = "$parent" ] || [ "$p" = "$self" ]; then continue; fi
if [ -n "$sig" ]; then
kill "$sig" "$p" 2>/dev/null && out=1
else
kill -TERM "$p" 2>/dev/null && out=1
fi
done
[ "$out" -eq 1 ] && exit 0
exit 1
'''
.replaceAll('__FA_REAL_PKILL__', realPkill)
.replaceAll('__FA_REAL_PGREP__', realPgrep);