⬢ DragonFlyBSD Kernel Audit
DF-5356 / extract2.sh
← back to finding ↓ download raw
#!/bin/sh
# extract2.sh -- machine-extract the PRODUCTION pccard.c lifecycle code
# (attach/detach card, function init/free/enable/disable, pnpinfo) plus the
# PRODUCTION resource_list_* core from kern/subr_bus.c, byte-identical, from
# the guest's own /usr/src kernel tree, into include-able .inc files for the
# userland verification rig2 (DF-2318 / DF-5355 / DF-5356).
#
# sha256-gated like DF-2319's extract.sh:
#   PRISTINE  -> sed fixed line-ranges (byte-identical by construction),
#                cross-checked against the awk function-extractor.
#   PATCHED   -> awk anchor-based function extraction (fixes shift lines),
#                requires --allow-patched.
#
# Usage: sh extract2.sh <outdir> [srctree] [--allow-patched]
#   srctree default /usr/src/sys  (use a patched COPY for fix variants)
set -eu

OUT="${1:-.}"
TREE="${2:-/usr/src/sys}"
ALLOW="${3:-}"
SRC="$TREE/bus/pccard"
KBUS=/usr/src/sys/kern/subr_bus.c   # never patched in this run; always pristine

# Pristine sha256 of the audit tree.
P_PCCARD_C=5b61066925991ec0776510142c6280cffca5c94e317a06f480744da3736b8d5e
P_CIS_C=acdd2484925fd5f09ab7266fcbb575134ae73e72c20f3e844c236ef0c2c2304c
P_VAR_H=3e73a8771c78e6aa9e52c764f1431571b835674ec87aecb4d32575c6dcdb4141
P_CISH=9ed5d42411f363810ead8c9a6fd7e67abda1700504342325bb03fc281c8e0959
P_REG_H=55e55e8a7be4784ed1400c9de2c7dd72455e08b053dda985cb43e2fe2eb80309
P_SUBR_BUS=949f75de6c72fbbd3af7f23caf87aec6d2ed179744a738c6dd73149c1d091824
P_SYSBUS_H=4d01db59f8fe410b299041a33ccbbe08f230e008555f8af4a11fdc9291eea7e0
P_QUEUE=6072482fad8732b5ea0f315ed0fc0acd7abd02c3f8180c0733ea1b8c671d0745

h() { sha256 -r "$1" | awk '{print $1}'; }

mkdir -p "$OUT"
MAN="$OUT/extract2_manifest.txt"
{
	echo "=== verbatim extraction manifest (rig2: pccard.c lifecycle) ==="
	date
	uname -a
	echo "srctree=$TREE"
} > "$MAN"

STATE=PRISTINE
check() { # name file pristhash
	got=$(h "$2")
	if [ "$got" = "$3" ]; then
		echo "VERBATIM_CHECK $1 PRISTINE $got" | tee -a "$MAN"
	else
		echo "VERBATIM_CHECK $1 PATCHED  $got (pristine=$3)" | tee -a "$MAN"
		STATE=PATCHED
	fi
}

check pccard.c      "$SRC/pccard.c"      "$P_PCCARD_C"
check pccard_cis.c  "$SRC/pccard_cis.c"  "$P_CIS_C"
check pccardvar.h   "$SRC/pccardvar.h"   "$P_VAR_H"
check pccard_cis.h  "$SRC/pccard_cis.h"  "$P_CISH"
check pccardreg.h   "$SRC/pccardreg.h"   "$P_REG_H"
check subr_bus.c    "$KBUS"              "$P_SUBR_BUS"
check sys/bus.h     /usr/src/sys/sys/bus.h "$P_SYSBUS_H"
check queue.h       /usr/src/sys/sys/queue.h "$P_QUEUE"
check queue.h.usrinc /usr/include/sys/queue.h "$P_QUEUE"

if [ "$STATE" = PATCHED ] && [ "$ALLOW" != "--allow-patched" ]; then
	echo "REFUSING: source tree is PATCHED and --allow-patched not given" | tee -a "$MAN"
	exit 3
fi
echo "SOURCE_STATE=$STATE" | tee -a "$MAN"

# ---- function extractor: from the type line above '^name(' to the first
# ---- '^}' (BSD kernel style: no column-0 braces inside function bodies).
ef() { # file name  -- emits function text (type line .. closing brace)
	n=$(grep -nE "^$2\(" "$1" | head -1 | cut -d: -f1)
	if [ -z "$n" ]; then echo "EXTRACT_FAIL:$2" >&2; exit 4; fi
	s=$((n - 1))
	tl=$(sed -n "${s}p" "$1")
	case "$tl" in
		*\;*) echo "EXTRACT_FAIL:$2 type-line is a prototype: $tl" >&2; exit 4 ;;
	esac
	awk -v s=$s 'NR>=s { print; if ($0 ~ /^}/) exit }' "$1"
	echo "$s:$n" >> "$OUT/func_lines.txt"
}

: > "$OUT/func_lines.txt"

# ---- pccard.c functions (verbatim) -------------------------------------
{
	sed -n '83,90p' "$SRC/pccard.c"		# production forward decls
	ef "$SRC/pccard.c" pccard_ccr_read
	ef "$SRC/pccard.c" pccard_ccr_write
	ef "$SRC/pccard.c" pccard_set_default_descr
	ef "$SRC/pccard.c" pccard_attach_card
	ef "$SRC/pccard.c" pccard_detach_card
	ef "$SRC/pccard.c" pccard_function_init
	ef "$SRC/pccard.c" pccard_function_free
	ef "$SRC/pccard.c" pccard_mfc_adjust_iobase
	ef "$SRC/pccard.c" pccard_function_enable
	ef "$SRC/pccard.c" pccard_function_disable
	ef "$SRC/pccard.c" pccard_safe_quote
	ef "$SRC/pccard.c" pccard_child_pnpinfo_str
	ef "$SRC/pccard.c" pccard_read_ivar
} > "$OUT/pccard_core.inc"

# debug macros + PCCARDDEBUG define (not functions):
if [ "$STATE" = PRISTINE ]; then
	sed -n '55p;71,81p' "$SRC/pccard.c" > "$OUT/pccard_macros.inc"
else
	awk '/^#define PCCARDDEBUG$/ {print; exit}' "$SRC/pccard.c" > "$OUT/pccard_macros.inc"
	awk 'f{print; if($0 ~ /^#endif/) exit} /^#ifdef PCCARDDEBUG$/{f=1; print}' \
	    "$SRC/pccard.c" >> "$OUT/pccard_macros.inc"
fi

# ---- pccard_cis.c parser (verbatim; same ranges as DF-2319) -------------
if [ "$STATE" = PRISTINE ]; then
	sed -n '51,444p;612,1294p' "$SRC/pccard_cis.c" > "$OUT/pccard_cis_core.inc"
else
	awk 'f && NR>=b1 && NR<=b2 {print} ' /dev/null 2>/dev/null || true
	A1=$(grep -n '^extern int	pccard_cis_debug;' "$SRC/pccard_cis.c" | cut -d: -f1)
	A2=$(grep -n '^/\* XXX this is incredibly verbose' "$SRC/pccard_cis.c" | cut -d: -f1)
	B1=$(grep -n '^pccard_parse_cis_tuple(const struct pccard_tuple \*tuple, void \*arg)$' \
		"$SRC/pccard_cis.c" | cut -d: -f1)
	B1=$((B1 - 1))
	B2=$(wc -l < "$SRC/pccard_cis.c")
	sed -n "${A1},$((A2 - 2))p;${B1},${B2}p" "$SRC/pccard_cis.c" > "$OUT/pccard_cis_core.inc"
	echo "anchor ranges: ${A1},$((A2-2)) and ${B1},${B2} (patched layout)" >> "$MAN"
fi

# ---- pccardvar.h struct/macro ranges (verbatim; superset of DF-2319) ----
sed -n '62,70p;74,126p;128,160p;165,203p;213,222p;250,252p;161,163p;255,292p;322,335p;336,367p' \
	"$SRC/pccardvar.h" > "$OUT/pccardvar2.inc"

# ---- constant headers (whole-file copies) ------------------------------
cp "$SRC/pccard_cis.h"  "$OUT/pccard_cis.h"
cp "$SRC/pccardreg.h"   "$OUT/pccardreg.h"

# ---- kern/subr_bus.c resource_list core (verbatim; always pristine) ----
{
	sed -n '164,186p' /usr/src/sys/sys/bus.h	# production prototypes
	ef "$KBUS" resource_list_init
	ef "$KBUS" resource_list_free
	ef "$KBUS" resource_list_add
	ef "$KBUS" resource_list_find
	ef "$KBUS" resource_list_delete
	ef "$KBUS" bus_child_pnpinfo_str
} > "$OUT/subrbus_rl.inc"

# ---- sys/sys/bus.h resource_list_entry struct (verbatim) ----------------
sed -n '136,146p' /usr/src/sys/sys/bus.h > "$OUT/sysbus_rl.inc"

# ---- pristine byte-identity cross-check (sed fixed ranges vs awk) ------
# ranges verified against the pristine audit tree:
#   pccard.c:   55; 71-81; 150-175; 177-289; 291-326; 407-503; 512-538;
#               540-574; 577-698; 701-755; 992-1009; 1011-1026; 1028-1072
#   subr_bus.c: 2594-2598; 2600-2611; 2613-2644; 2646-2656; 258-2670 typo-guard;
#               2658-2670; 3433-3444
if [ "$STATE" = PRISTINE ]; then
	sed -n '55p;71,81p;83,90p;134,139p;141,148p;150,175p;177,289p;291,326p;407,503p;512,538p;540,574p;577,698p;701,755p;992,1009p;1011,1026p;1028,1072p' \
		"$SRC/pccard.c" > "$OUT/.pc_sedref"
	sed -n '2594,2598p;2600,2611p;2613,2644p;2646,2656p;2658,2670p;3433,3444p' \
		"$KBUS" > "$OUT/.sb_sedref"
	echo "pccard.c sed-vs-awk byte diff (empty=identical):" >> "$MAN"
	cat "$OUT/pccard_core.inc" "$OUT/pccard_macros.inc" > "$OUT/.pc_concat"
	# awk emits functions in listed order; compare sorted content (the sha256
	# gate on the pristine source is the primary byte-identity guarantee).
	sort "$OUT/.pc_concat" > "$OUT/.pc_a"
	sort "$OUT/.pc_sedref" > "$OUT/.pc_b"
	if cmp -s "$OUT/.pc_a" "$OUT/.pc_b"; then
		echo "PCCARD_BYTE_IDENTICAL=yes" | tee -a "$MAN"
	else
		echo "PCCARD_BYTE_IDENTICAL=NO (see below)" | tee -a "$MAN"
		diff "$OUT/.pc_a" "$OUT/.pc_b" | head -20 >> "$MAN" || true
	fi
	tail -n +24 "$OUT/subrbus_rl.inc" | sort > "$OUT/.sb_a"  # skip proto block
	sort "$OUT/.sb_sedref" > "$OUT/.sb_b"
	if cmp -s "$OUT/.sb_a" "$OUT/.sb_b"; then
		echo "SUBR_BUS_BYTE_IDENTICAL=yes" | tee -a "$MAN"
	else
		echo "SUBR_BUS_BYTE_IDENTICAL=NO" | tee -a "$MAN"
		diff "$OUT/.sb_a" "$OUT/.sb_b" | head -20 >> "$MAN" || true
	fi
	rm -f "$OUT/.pc_sedref" "$OUT/.sb_sedref" \
	      "$OUT/.pc_concat" "$OUT/.pc_a" "$OUT/.pc_b" "$OUT/.sb_a" "$OUT/.sb_b"
fi

{
	echo "--- artifacts ---"
	cat "$OUT/func_lines.txt" | sed 's/^/func_lines /'
	sha256 -r "$OUT/pccard_core.inc" "$OUT/pccard_macros.inc" \
		"$OUT/pccard_cis_core.inc" "$OUT/pccardvar2.inc" \
		"$OUT/subrbus_rl.inc" "$OUT/sysbus_rl.inc" \
		"$OUT/pccard_cis.h" "$OUT/pccardreg.h"
	echo "bytes core=$(wc -c < "$OUT/pccard_core.inc") cis=$(wc -c < "$OUT/pccard_cis_core.inc") rl=$(wc -c < "$OUT/subrbus_rl.inc")"
} >> "$MAN"

echo "EXTRACT2_OK state=$STATE"