DF-2256 / verdict.json
{ "finding_id": "DF-2256", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "certain", "verdict": "Reproduced through the byte-identical code compiled into the guest kernel. (1) ar9300_calibration_data_read_array(ah, 2, buf, 16) on a working device: the 13 negative-address reads are rejected inside the verbatim read_eeprom, their slots keep the pre-call sentinel, and the function still returns AH_TRUE - the (void) cast at ar9300_eeprom.c:3703 plus unconditional AH_TRUE at :3705 is exactly as claimed. (2) Amplifier: after a successful parse leaves a length=2047 header in the dead word[] stack slots, a device that goes dark makes the next header read fail; the blank-check and ar9300_compression_header_unpack then derive length=2047 from the uninitialized stack and the payload read_array is asked for 2053 bytes into word[2048] (counter trace 4104 failed device reads) - stale stack drives many beyond the buffer, feeding DF-2255. (3) On a 2KB device word[2048..2052] stay uninitialized and are consumed by the checksum loop and the mchecksum loads at word[4+length],word[5+length]. Direct impact is a correctness/uninitialized-data defect (Low): the claimed userspace readout needs a non-default AH_PRIVATE_DIAG+ATH_DIAGAPI kernel and a ~2^-16 checksum coincidence over garbage, so it stays theoretical; no unprivileged local input path exists (card EEPROM/OTP is the input). fix.diff (propagate per-byte failure as AH_FALSE plus break at both call sites) validated on a rebuilt kernel: arrfail returns AH_FALSE with slots never written, uninit aborts after 1 failed read, and the legitimate all-reads-succeed path still restores 16/16 marker bytes.", "exploit_chain": "", "evidence": "run.log: baseline arrfail buf dump 11 22 33 cc x13 with retval AH_TRUE (*** DF-2256 CONFIRMED ***); uninit amplifier line (length=2047 from UNINITIALIZED stack, 2053-byte read, *** DF-2256 AMPLIFIER CONFIRMED ***); otp2k 5/5 sentinel slots consumed by checksum/mchecksum; post-fix section shows FIX EFFECTIVE (AH_FALSE propagated, abort after 1 read) with chk 16/16 unchanged; differential section (fix2255-only kernel #7) shows DF-2256 still live. logs/extract_baseline.log: sha256 gate 75771111... env.txt: kernel/boot mapping.", "kernel_refs": [ "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c:3697", "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c:3703", "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c:3705", "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c:3903", "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c:3905", "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c:3923", "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c:3929", "sys/contrib/dev/ath/ath_hal/ar9300/ar9300_misc.c:1207" ], "poc_changes": "Shared rig with DF-2255 (see that pack): authored the sha256-gated verbatim extractor and kernel-compiled harness, fake EEPROM device with per-word failure control, stack groom between two same-depth verbatim calls to model prior stack users, sentinel window capture. Same 8 harness iterations; DF-2256-specific cases needed the iteration-1 header replant and stub-level vs pre-stub rejection accounting (13 negative-address rejects happen above the device stub).", "attempts": 8, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #9: Sat Oct 17 17:54:41 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline evidence on kernels #3/#5/#6, fix validation on #9; see env.txt)", "runtime_sec": 3900, "guest_dirty": 0, "build_cmd": "cd /root/df2255 && sh build.sh (extract.sh sha256-gated byte-identical extraction; cp df2255_harness.c df2255_verbatim.inc /usr/src/sys/kern/; printf kern/df2255_harness.c\\tstandard >> /usr/src/sys/conf/files; cd /usr/src && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC; fix validation via make -j6 quickkernel)", "run_cmd": "sysctl -w kern.df2255.rig=arrfail ; sysctl -w kern.df2255.rig=uninit ; sysctl -w kern.df2255.rig=otp2k ; dmesg | grep DFH: (root, in-guest)", "code_hash": "53682c234e17482afc91927d7d896297b2f5080371d0d22298f237e8dfcec887", "notes": "CONTRIB vendored QCA HAL - upstream owns the fix; FreeBSD head 2026-10-17 still ships the (void) read pattern (its lines 3759/3959/3979). Impact recorded as none for this finding alone: the leak readout (HAL_DIAG_EEPROM -> SIOCGATHDIAG) is compiled only on non-default AH_PRIVATE_DIAG+ATH_DIAGAPI builds and gated on a ~2^-16 checksum coincidence; the practical effect is uninit-stack consumption plus the DF-2255 amplifier. The SIOCGATHDIAG read path itself has no privilege check (if_ath_ioctl.c:299) - worth a separate hardening look for ATH_DIAGAPI builds.", "recommended_fix": "Make ar9300_calibration_data_read_array return AH_FALSE on the first per-byte read failure and have both call sites in ar9300_eeprom_restore_internal_address break out of the block scan instead of parsing a partially-filled word[]." } |