DF-1090 / verify.sh
#!/bin/sh # DF-1090 static source-verification script. # Confirms each affected descriptor type accesses fixed offsets without a length check. set +e PASS=0; FAIL=0 check() { if eval "$2"; then echo "PASS $1" PASS=$((PASS+1)) else echo "FAIL $1" FAIL=$((FAIL+1)) fi } F=sys/bus/isa/pnpparse.c # Each affected case (unpatched) accesses offsets without len check check "PNP_TAG_COMPAT_DEVICE bcopy(res,4) without len<4 guard" \ 'awk "/case PNP_TAG_COMPAT_DEVICE/,/break/" '"$F"' | grep -q "bcopy(res, &compat_id, 4)" && ! awk "/case PNP_TAG_COMPAT_DEVICE/,/break/" '"$F"' | grep -q "if (len < 4)"' check "PNP_TAG_IRQ_FORMAT I16(res) without len<2 guard" \ 'awk "/case PNP_TAG_IRQ_FORMAT/,/case PNP_TAG_DMA_FORMAT/" '"$F"' | grep -q "I16(res) == 0" && ! awk "/case PNP_TAG_IRQ_FORMAT/,/case PNP_TAG_DMA_FORMAT/" '"$F"' | grep -q "if (len < 2)"' check "PNP_TAG_DMA_FORMAT res[0] without len<1 guard" \ 'awk "/case PNP_TAG_DMA_FORMAT/,/case PNP_TAG_IO_RANGE/" '"$F"' | grep -q "res\[0\] == 0" && ! awk "/case PNP_TAG_DMA_FORMAT/,/case PNP_TAG_IO_RANGE/" '"$F"' | grep -q "if (len < 1)"' check "PNP_TAG_IO_RANGE res[6]/res[5]=1 without len<7 guard" \ 'awk "/case PNP_TAG_IO_RANGE/,/case PNP_TAG_IO_FIXED/" '"$F"' | grep -qE "res\[6\]|res\[5\] = 1" && ! awk "/case PNP_TAG_IO_RANGE/,/case PNP_TAG_IO_FIXED/" '"$F"' | grep -q "if (len < 7)"' check "PNP_TAG_IO_FIXED res[2]/I16(res) without len<3 guard" \ 'awk "/case PNP_TAG_IO_FIXED/,/case PNP_TAG_END:/" '"$F"' | grep -q "res\[2\] == 0" && ! awk "/case PNP_TAG_IO_FIXED/,/case PNP_TAG_END:/" '"$F"' | grep -q "if (len < 3)"' check "PNP_TAG_MEMORY_RANGE I16(res+7) without len<9 guard" \ 'awk "/case PNP_TAG_MEMORY_RANGE/,/case PNP_TAG_MEMORY32_RANGE/" '"$F"' | grep -q "I16(res + 7)" && ! awk "/case PNP_TAG_MEMORY_RANGE/,/case PNP_TAG_MEMORY32_RANGE/" '"$F"' | grep -q "if (len < 9)"' check "PNP_TAG_MEMORY32_RANGE I32(res+13) without len<17 guard" \ 'awk "/case PNP_TAG_MEMORY32_RANGE/,/case PNP_TAG_MEMORY32_FIXED/" '"$F"' | grep -q "I32(res + 13)" && ! awk "/case PNP_TAG_MEMORY32_RANGE/,/case PNP_TAG_MEMORY32_FIXED/" '"$F"' | grep -q "if (len < 17)"' check "PNP_TAG_MEMORY32_FIXED I32(res+5) without len<9 guard" \ 'awk "/case PNP_TAG_MEMORY32_FIXED/,/default:/" '"$F"' | grep -q "I32(res + 5)" && ! awk "/case PNP_TAG_MEMORY32_FIXED/,/default:/" '"$F"' | grep -q "if (len < 9)"' # PNP_TAG_ID_ANSI is the one that DOES clamp len correctly check "PNP_TAG_ID_ANSI correctly clamps len before bcopy (control case)" \ 'awk "/case PNP_TAG_ID_ANSI/,/device_set_desc_copy/" '"$F"' | grep -q "len > sizeof(buf) - 1"' # Function signature: len is signed int, no clamp on entry check "pnp_parse_desc signature has no clamp" \ 'grep -q "pnp_parse_desc(device_t dev, u_char tag, u_char \*res, int len," '"$F"'' # pnpparse.c calls pnp_parse_desc with attacker-controlled len from TLV check "pnpparse.c passes attacker-controlled TLV length to pnp_parse_desc" \ 'grep -q "pnp_parse_desc(dev, tag, p, l, config, ldn)" sys/bus/isa/pnpparse.c' echo echo "PASS=$PASS FAIL=$FAIL" [ "$FAIL" -eq 0 ] |