Unbounded kk pdadc walk writes past pcdacTable[PWR_TABLE_SIZE_2317=128] β 80-byte intra-object heap OOB write into RF bank scratch (twin of DF-4619/4648/4660)
Summary
The three pdadc write loops share kk with no bound; minimum-guaranteed walk for 4 gains is 156>128 (measured kk=168, 80 bytes into the RF bank scratch reprogrammed to the radio). VERBATIM-EXTRACTION harness on guest REPRODUCES with canary; fix validated -> no overflow. Cap-kk fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4680 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.6 KB | β raw | |
| VERDICT.md | β | 2.8 KB | β raw | |
| ar2317_harness.c | β | 16.5 KB | view raw | |
| build.sh | β | 85 B | view raw | |
| run.sh | β | 99 B | view raw | |
| fix_validate.sh | β | 2.8 KB | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| build.log | β | 686 B | view raw | |
| run.log | β | 3.0 KB | view raw | |
| fix_run.log | β | 8.6 KB | view raw | |
| env.txt | β | 844 B | view raw | |
| manifest.json | β | 916 B | view raw | |
| verdict.json | β | 4.1 KB | view raw |
DF-4680 β ar2317: unbounded kk pdadc walk writes past pcdacTable[128]
Twin of DF-4619 (ar5413) / DF-4648 (ar2316) / DF-4660 (ar2413), verified for
sys/dev/netif/ath/ath_hal/ar5212/ar2317.c.
Build (on the DragonFly guest)
cd /root/df2317 && sh build.sh
build.sh copies the pristine /usr/src/.../ar2317.c (md5-verified equal to
the audit tree), verbatim-extracts lines ~228-477 (GetLowerUpperIndex,
ar2317FillVpdTable, interpolate_signed,
ar2317getGainBoundariesAndPdadcsForPowers) by anchor, and compiles them
against a faithful struct ar2317State (bank rows 1/1/1/30/3 from the shipped
ar5212.ini).
Run
./ar2317_harness 1 # this finding ./ar2317_harness 2|3 # siblings DF-4681 / DF-4682 (same pack set) ./ar2317_harness 4|5 # DF-4683 sh run.sh # all five modes + uninit-variance repeats
Expected (baseline)
DF-4680 REPRODUCED: pPDADCValues write walked past pcdacTable[127]: first clobbered u16 cell 0 bytes past array end, last 79 bytes past (value 0x007f) => kk ran to 168
kk is bounded by nothing in the three pPDADCValues[kk++] loops
(ar2317.c:434/:443/:457); with 4 used gains, 63-clamped gain boundaries and
TPCRG5 overlap 15 the guaranteed minimum walk is 156 > 128, so the tail of the
pdadc table spills 80 bytes into Bank1Data..Bank7Data (RF bank scratch,
reprogrammed to the radio at ar2317.c:190-194).
Fix validation
sh fix_validate.sh # applies fixA..fixD to copies, re-extracts, re-runs
fixA (this pack's fix.diff) caps kk at PWR_TABLE_SIZE_2317 in all three
loops β patched mode 1 prints DF-4680: NO overflow detected.
DF-4680 β VERDICT
Status: REPRODUCED (guest, verbatim-extraction harness) Β· impact: dos Β· confidence: certain Β· fix: fixed (validated)
What was verified
The three pPDADCValues[kk++] loops in
ar2317getGainBoundariesAndPdadcsForPowers() β extrapolate-below
(ar2317.c:432-436), main walk (:442-443), extrapolate-above (:452-461) β share
one running index kk into pPDADCValues with no bound. pPDADCValues
is ahp->ah_pcdacTable (ar2317.c:490), aliased to
priv->pcdacTable[PWR_TABLE_SIZE_2317=128] at attach (ar2317.c:729;
PWR_TABLE_SIZE_2413 = 128, ah_eeprom_v3.h:282).
The harness compiles the guest's own function bodies (anchor-extracted from
/usr/src, md5-verified) against the faithful struct (offsets printed in
build.log: pcdacTable@72, Bank1Data@328, vpdTable_L@472, sizeof=2008) and
drives them with an EEPROM-shaped dataset identical in shape to what the
shared SetupRawDataset produces (xpd_mask=0xF, four gains with numVpd=4,
Pmin pattern {0,58,58,58}, TPCRG5 overlap 15 β the mask field is 4 bits,
ar5212phy.h:349).
Observed (run.log, mode 1): kk ran to 168; cells 128..167 (80 bytes)
landed in Bank1Data..Bank7Data (0xAAAAAAAA canary destroyed, values
0x0000..0x007F). The overwritten banks are written to the radio by
ar2317SetRfRegs (ar2317.c:190-194) β radio misprogramming at best, crash at
worst. The overflow is intra-object (stays inside the 2008-byte
ath_hal_malloc allocation) and written values are clamped (0/127), so there
is no uid0 route; severity Low, consistent with the ar5413/ar2316/ar2413
twins.
Why the bound cannot hold on legit-looking data
Worst-case per-gain walk = extrapolate-below (ss from
boundary[ii-1]-Pmin[ii]-overlap, can be β -(63+15)) + main (maxIndex β€
63) + extrapolate-above (up to 63+15-0). With the minimum-guaranteed sum
3+63+6Γ15 = 156 > 128 for the last gain alone, and up to 4 gains contributing,
the overflow needs no malformed EEPROM beyond ordinary-looking cal data.
Fix validation
fix.diff = kk < PWR_TABLE_SIZE_2317 guards on all three loops.
fix_validate.sh applies it to a copy of the pristine guest source,
re-extracts verbatim, rebuilds, re-runs: patched mode 1 β
DF-4680: NO overflow detected (canary intact). git apply --check clean
against sys/; never applied to sys/.
Not re-reported
DF-1806 (pass 1, numChannels==0 β idxL/idxR wild reads) β different trigger, different guard. Siblings DF-4681 / DF-4682 / DF-4683 cover the other defects in the same function.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
fixedValidated on the guest: fix.diff (kk < PWR_TABLE_SIZE_2317 guards on all three pPDADCValues[kk++] loops) applied to a copy of the pristine guest ar2317.c, function bodies re-extracted verbatim from the patched copy, harness rebuilt and re-run. Baseline reproduces the overflow; patched build shows 'DF-4680: NO overflow detected' (bank canary intact). fix.diff is git-apply-able against the pristine tree (git apply --check clean) and was never applied to sys/.
fix_run.log ('===== fixA' section: PATCHES_APPLIED, FIXED_BUILD_OK, 'NO overflow detected') vs run.log mode 1; fix.diff in pack.
Confirmed kernel references
- sys/dev/netif/ath/ath_hal/ar5212/ar2317.c:432-436
- sys/dev/netif/ath/ath_hal/ar5212/ar2317.c:442-443
- sys/dev/netif/ath/ath_hal/ar5212/ar2317.c:452-461
- sys/dev/netif/ath/ath_hal/ar5212/ar2317.c:41
- sys/dev/netif/ath/ath_hal/ar5212/ar2317.c:490
- sys/dev/netif/ath/ath_hal/ar5212/ar2317.c:729
- sys/dev/netif/ath/ath_hal/ar5212/ar2317.c:190-194
- sys/dev/netif/ath/ath_hal/ah_eeprom_v3.h:282
Detail
Exploit chain
crafted v3 EEPROM on AR2317 card -> ath attach reads ee_rawDataset2413 -> ar5212SetTransmitPower (ar5212_reset.c:2006-2036) -> ar2317SetPowerTable:513-515 -> ar2317getGainBoundariesAndPdadcsForPowers unbounded kk walk -> 80-byte intra-object heap OOB write past pcdacTable[128] into RF bank scratch -> banks programmed to radio (ar2317.c:190-194): radio misprogramming / crash. No uid0 route (values clamped 0..127, intra-object only).
Evidence (decisive lines)
run.log mode 1: 'DF-4680 REPRODUCED ... kk ran to 168'; build.log struct offsets (pcdac@72 Bank1@328 vpdTable_L@472 sizeof 2008); fix_run.log patched mode 1: 'NO overflow detected'; fix.diff (git-apply verified vs sys/).
PoC changes
Harness ported from the DF-4660 (ar2413) twin: bank row counts 1/1/1/30/3 (ar5212.ini ar5212Bank*_2317), ar2317 names/anchors, 72-cell bank canary window, ar2317.c:35-37 typedef aliases added ahead of the extraction, object placed at a page end with a guard page (shared with modes 4/5 of DF-4683). No kernel-code changes -- function bodies compiled verbatim.
Verified recommended fix
Add kk < PWR_TABLE_SIZE_2317 guards to all three pPDADCValues[kk++] loops in ar2317getGainBoundariesAndPdadcsForPowers (fix.diff).
Verdict
REPRODUCED on the DragonFly guest (verbatim-extraction harness, mode 1): with an EEPROM-shaped crafted dataset (xpd_mask=0xF, Pmin pattern {0,58,58,58}, TPCRG5 overlap 15 -- register-realistic, the field is 4 bits, ar5212phy.h:349) the unbounded kk walk at ar2317.c:434/:443/:457 wrote 40 uint16 cells (80 bytes) past pcdacTable[PWR_TABLE_SIZE_2317=128] into the Bank1Data..Bank7Data members of the heap-allocated ar2317State object (intra-object overflow; RF bank scratch corrupted, reprogrammed to the radio at ar2317.c:190-194). kk ran to 168; with 63-clamped boundaries and overlap 15 the minimum-guaranteed walk is 3+63+6*15=156 > 128. Exploitation is gated on attacker-supplied AR2317 hardware with crafted EEPROM (physical/supply-chain); realistic ceiling is radio misprogramming/DoS, not privilege escalation. Twin of DF-4619 (ar5413) / DF-4648 (ar2316) / DF-4660 (ar2413). Fix validated: with kk<PWR_TABLE_SIZE_2317 guards the overflow is gone (bank canary intact, fix_run.log).
No comments yet.