β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4396

CENTRAL FIX: Vega10 PowerPlay parser has no bounds-validation layer β€” all 22 firmware USHORT offsets, every UCHAR count and every revision dispatch consumed unvalidated against soft_pp_table_size (vega10 side of DF-4388)

Summary

The Vega10 parser consumes everything with zero range validation: subtable pointers computed as base + raw u16 offset and dereferenced (one entry-count helper with NO validation at all); every u8 count sizes both the kzalloc and the source-read loop (7 MM/clk families incl. the 12-byte GFXCLK V2 walk); rev dispatches over-read larger structs from possibly-shorter subtables; and init_dpm_2 clobbers 'result' per lookup so a failing VDDC lookup is masked - parse 'succeeds' with NULL tables that consumers deref (the DF-3702 crash list). DF-4388's V1 helper is NOT reusable verbatim (different struct family) - the layer is re-authored. CENTRAL FIX (564 lines, git-apply OK, kernel-toolchain syntax-validated, 22/22 clamp tests PASS incl. the DF-1586/1588/4395 neutralization cases). NEUTRALIZATION: kills knowns DF-1586/1587/1588/1589 and starves the vega10_hwmgr consumers (DF-1179..1183/3701..3707) of wild counts; per-file fixes stand as defense in depth.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4396 Β· 20 files
FileTypeDescriptionSize
rig/gen_rig.sh β€” 4.1 KB view raw
rig/check_verbatim.sh β€” 3.4 KB view raw
rig/rig_shims.h β€” 6.2 KB view raw
rig/vega10_rig.c β€” 43.9 KB view raw
rig/Makefile β€” 494 B ↓ download
rig/build.sh β€” 501 B view raw
rig/run.sh β€” 1.0 KB view raw
fix.diff β€” 20.1 KB view raw
build.sh β€” 134 B view raw
run.sh β€” 133 B view raw
build.log β€” 2.9 KB view raw
run.log β€” 25.8 KB view raw
run.2.log β€” 25.8 KB view raw
run.3.log β€” 25.8 KB view raw
leak_sample.txt β€” 1.8 KB view raw
env.txt β€” 1.0 KB view raw
README.md β€” 6.8 KB ↓ raw
VERDICT.md β€” 8.5 KB ↓ raw
manifest.json β€” 3.0 KB view raw
verdict.json β€” 7.5 KB view raw

DF-4396 β€” CENTRAL FIX: Vega10 PowerPlay parser has no bounds-validation layer

Severity: High | Bucket: kernleak | Verified: REPRODUCED (verbatim-rig evidence class, same as DF-4165/DF-4247) + fix A/B-validated (fixed) on the identical inputs.

Status

Every defect family cited by the finding was demonstrated in byte-identical production parser code (vega10_processpptables.c:34-1326, machine-extracted and checker-verified on the DragonFly guest against /usr/src/sys β€” the tree its running kernel was compiled from), compiled into a harness and driven with crafted ATOM_Vega10_* PowerPlay tables β€” 16 SIGSEGV-confirmed unclamped accesses (12 source OOB reads incl. two +65,281-byte deep-offset reads, one NULL deref, two heap OOB writes past kzalloc'd objects), two byte-exact kernel-heap leak proofs (73 OOB records), two attacker-controlled heap-overflow canaries (247/247 and 1232 bytes byte-exact), and the result-clobbering masked failure (DF-3702 feeder). In-kernel execution remains AMD-ASIC-gated on this guest (no 0x1002 device, no /dev/dri, no amdgpu module β€” env.txt). The pack's fix.diff was A/B-validated in the same rig: every crafted mode clean, valid tables parse identically (no regression).

Rig layout (rig/)

  • gen_rig.sh sed-extracts the entire parser body (lines 34-1326) plus 22 verbatim struct/type header slices (the whole packed ATOM_Vega10_* family in vega10_pptable.h:26-419, the phm_ppt_v1_* kernel-side types, hwmgr/hardwaremanager/power_state slices) β€” bracketed with VERBATIM markers.
  • check_verbatim.sh re-proved all 23 blocks byte-identical on the guest against /usr/src/sys (build.log: ALL VERBATIM CHECKS PASSED), and that pp_slice_fixed.inc is exactly pristine+fix.diff (forward apply fuzz=0, slice equal, reverse apply restores pristine byte-exactly).
  • rig_shims.h touches no defect path: identity le*_to_cpu, three-mode kzalloc (plain / page-guarded destination / 0xAA-canary tail), minimized struct pp_hwmgr/amdgpu_device/pci_dev with production names/types for every field the parser and the fix consult, verbatim PP_ASSERT_WITH_CODE.
  • Crafted images mimic the ATOM Vega10 PowerPlay table a crafted/corrupt VBIOS (or a root-written pp_table sysfs blob β€” amd_powerplay.c:671-706) feeds the driver on a Vega10 board; images end at a 22-page PROT_NONE tail (deep u16-offset reads fault deterministically) or at a patterned victim region (leak provenance).

Observed (run.log / run.2.log / run.3.log β€” fault-offset fingerprints identical across 3 runs)

mode (crafted input) baseline (verbatim) fixed (+fix.diff)
clean-valid (full table) rc=0, 23/23 checks OK identical (no regression)
statearray-offset-oob (usStateArrayOffset=0xFF00, 128B image) SIGSEGV image+65281 (:82) rc=-1 "out of range"
numentries-offset-oob (direct :1249 call) SIGSEGV image+65281 rc=-1
thermal-offset-oob (:134) SIGSEGV image+65281 rc=-EINVAL
fan-v2-tail (rev 11 header, 1 byte in image) SIGSEGV image_end+31 (:214) rc=-EINVAL
od-acg-count-255 (rev1, entries[254].ucACGEnable) SIGSEGV image_end+3298 (:273, DF-1589) rc=0, clamped
gfxclk-v1-count-255 (:620 walk) SIGSEGV image_end+4 rc=0, count clamped to 1
socclk / mclk / pixclk / mm count-255 SIGSEGV image_end+0..4 rc=0, counts clamped to image
powertune-v3-short (rev7, 38B table, V3 fields) SIGSEGV image_end+0 (:488) rc=-EINVAL
hardlimit-tail (entries[0], no record) SIGSEGV image_end+0 (:814) rc=-1
pcie-null-sclk (gfxclk offset 0) SIGSEGV addr 0x0 (:781, DF-1587) rc=-EINVAL (NULL guard)
dcefclk-pioneer-write (dev 0x6863, count 255) SIGSEGV obj+232, alloc 228 (:740-748) rc=0, loop=8, no fault
dcefclk-pioneer-canary 1232 changed bytes in [+0,+6892] past the 228B object canary intact
vddc-lookup-write (count 255, max_levels 8) SIGSEGV obj+86, alloc 84 (:1036, DF-1586) rc=0, loop=8
vddc-lookup-canary 494 bytes changed [+2,+2463]; 247/247 us_vdd writes byte-exact with the image canary intact, count=8
gfxclk-v2-leak (rev1 count 40, 2 records) count=40; 38 OOB records byte-exact with victim bytes; od engineClock decided by the OOB ACG byte (LEAK) count=2; 0 OOB; decision bit in-image
socclk-leak-canary (count 40, 5 records) count=40; 35/35 OOB records byte-exact count=5, 0 OOB
result-clobber (vddc count 0, vddmem/vddci ok) rc=0 with NULL vddc_lookup_table (masked, DF-3702 feeder) rc=1 propagated
entry-offbyone (entry_index==ucNumEntries) SIGSEGV image_end+12 (:1308 <=, DF-1588) rc=-1 (< + range check)

Primitive and impact

The firmware image (VBIOS ROM copy or root-written sysfs blob) fully controls every offset (u16) and count (u8):

  • Heap OOB write, attacker-controlled: get_vddc_lookup_table (:1026-1038) writes up to 247Γ—2 bytes in a +2/+12/+22… stride 2463 bytes past an 84-byte kmalloc-128 object β€” 247/247 writes byte-exact with the crafted image; get_dcefclk_voltage_dependency_table pioneer path (:721-750) copies 255 records into a 228-byte kmalloc-256 object β€” overwrite reaches +6892 (~6.6 KB into adjacent slab objects).
  • Kernel-heap info leak: count-driven copy loops clone bytes from past the table image into hwmgr->dyn_state/pptable_info tables that userland reads back via powerplay sysfs (pp_dpm_*); even the overdrive-limit decision bit is taken from an OOB byte (gfxclk-v2-leak A/B).
  • Deep OOB reads / NULL deref (u16 offsets to +65,281; missing-subtable NULL at :781) β€” kernel panic paths.
  • Masked parse failure (:1103-1128) β€” NULL-table consumer crashes (DF-3702 class).

Gating: an AMD Vega10 ASIC whose VBIOS carries a crafted/corrupt PowerPlay table (flashed ROM, vfio romfile, malicious device), or root re-parsing via /sys/class/drm/card0/device/pp_table. No unprivileged trigger on stock hardware (same threat model as DF-4165/DF-4247).

Build / run (on the audit guest, or any DF box with the kernel tree)

scp -r rig fix.diff root@guest:/root/df4396/
cd /root/df4396 && ../df4396/build.sh /usr/src   # verbatim checks + 2 binaries
./run.sh                                          # baseline vs fixed, 23 modes

(The pre-verification pack carried a syntax-check + clamp-unit-test approach (vega10_clamp_test.c, vega10_processpptables_fixed.c) β€” superseded by this full verbatim-rig verification; files removed.)

Fix validation

fix.diff (564 lines) applied to the same verbatim slice (checker-proven equality with pristine+fix.diff): all crafted modes clean, all counts clamped to image/destination, NULL guarded, off-by-one fixed, failure propagated, clean-valid parses identically to baseline (no regression). The pack's fix.diff is the validated artifact, unchanged from the pre-verification version.

VERDICT.md
↓ download raw

DF-4396 VERDICT β€” central Vega10 PowerPlay validation layer

Status: REPRODUCED (verbatim-rig evidence class, DF-4165/DF-4247) | fix A/B-validated: FIXED | confidence: certain

Verification method

The entire production parser β€” vega10_processpptables.c:34-1326, every offset/count/index site β€” plus 22 struct/type header slices were machine-extracted from the kernel tree (rig/gen_rig.sh) and compiled into a harness on the DragonFly guest. rig/check_verbatim.sh re-proved all 23 VERBATIM blocks byte-identical against /usr/src/sys on the guest β€” the tree its running kernel (Jul 2 2026 build) was compiled from (build.log: ALL VERBATIM CHECKS PASSED; host/guest parser SHA256 equal in env.txt). The fixed build is the same slice with this pack's fix.diff applied via patch --fuzz=0 (bidirectionally proven: forward-apply + slice equality + reverse-apply restores the pristine file byte-exactly).

The rig's only non-production code (rig_shims.h) touches no defect path: identity endian helpers, a 3-mode kzalloc (plain / page-guarded destination / 0xAA canary), minimized pp_hwmgr/amdgpu_device/pci_dev with production names and types for every field the parser and the fix consult, and the verbatim PP_ASSERT_WITH_CODE. Crafted images end either at a 22-page PROT_NONE tail (deep-offset reads fault deterministically β€” a small guard let the +0xFF00 modes land in adjacent heap mappings in the first rig iteration, which is why the guard region is 22 pages) or at a deterministic victim pattern (leak provenance).

Every cited defect family proven (baseline = verbatim production code)

All numbers from run.log (fault-offset fingerprints identical across run.2.log/run.3.log β€” 3 runs, 16 SIGSEGVs each):

A. USHORT offsets dereferenced unvalidated (deep OOB reads + NULL deref) - check_powerplay_tables:72-82 β€” usStateArrayOffset=0xFF00 on a 128-byte image: state_arrays->ucNumEntries read at image+65281 β†’ SIGSEGV (+65153 past image end). - vega10_get_number_of_powerplay_table_entries:1246-1249 β€” the same offset, zero validation of any kind: SIGSEGV at image+65281. - init_thermal_controller:127-134 β€” usThermalControllerOffset=0xFF00: ucType read at image+65281 β†’ SIGSEGV. - get_pcie_table:781 β€” PCIE table present + usGfxclkDependencyTableOffset == 0 β†’ table_info->vdd_dep_on_sclk->count on NULL β†’ SIGSEGV at 0x0 (DF-1587).

B. u8 counts size alloc AND copy loop (source OOB reads β†’ kernel-heap leak) - socclk/mclk/pixclk (shared getter)/mm and the GFXCLK V1 walk: ucNumEntries =255 with 1-2 records in image β†’ SIGSEGV at image_end+0..4 in the copy loop. Leak legs (victim-pattern images): vdd_dep_on_socclk 35/35 OOB records and the GFXCLK V2 13-byte-stride walk 38/38 OOB records byte-exact with the bytes past the image β€” the cloned values surface to userland via powerplay sysfs (pp_dpm_*), exactly the DF-4247 leak class. - init_over_drive_limits:269-273 β€” rev-1 GFXCLK table, ucNumEntries=255, 1 record: patom_record_v2[254].ucACGEnable read 3298 bytes past image end β†’ SIGSEGV (the DF-1589 unclamped [count-1]). Leak leg: with the OOB byte readable, overdriveLimit.engineClock (sysfs-visible) is decided by that OOB byte while the last in-image record carries the opposite bit β€” byte-exact 1-bit leak provenance, A/B-decisive against the fixed build.

C. Rev dispatch over-reads larger structs from shorter subtables - fan table: header ucRevId=11 (V2) with only the header byte in image β†’ V2 field read at image_end+31 β†’ SIGSEGV (:210-254). - PowerTune: rev 7 (β†’V3) with a V2-sized 38-byte table β†’ usBoostStartTemperature read at image_end+0 β†’ SIGSEGV (:472-513). - hard limits: header claims 1 entry, no record bytes β†’ entries[0] read at image_end+0 β†’ SIGSEGV (:810-819).

D. Heap OOB WRITES past kzalloc'd destinations (attacker-controlled) - get_vddc_lookup_table:1026-1038 (DF-1586): alloc 4+8*10=84 (kmalloc-128 class), loop copies 255 β†’ dest-guard SIGSEGV at obj+86; canary run: 494 bytes changed in [+2,+2463], 247/247 OOB us_vdd writes byte-exact equal to the crafted image bytes (strided 2-byte writes, +2 every 10 bytes β€” fully attacker-controlled linear overflow of the adjacent slab object). - get_dcefclk_voltage_dependency_table:721-750 (pioneer, dev 0x6863 rev 0): alloc 4+8*28=228 (kmalloc-256), loop runs 255 β†’ dest-guard SIGSEGV at obj+232; canary run: 1232 bytes changed reaching +6892 past the object (~6.6 KB into adjacent slab objects; values = crafted-image clocks).

E. Masked parse failure (the DF-3702 NULL-table feeder) - init_dpm_2_parameters:1103-1128 β€” failing VDDC lookup (returns 1, leaves vddc_lookup_table==NULL) overwritten by succeeding VDDMEM/VDDCI lookups: parse returns rc=0 with a NULL table β€” reproduced exactly; consumers NULL-deref (vega10_hwmgr.c:293-313).

F. Off-by-one state entry (DF-1588) - vega10_get_powerplay_table_entry:1308 entry_index <= ucNumEntries lets entry_index==ucNumEntries pass β†’ states[N].usClassification read at image_end+12 β†’ SIGSEGV.

G. No regression: clean-valid β€” a complete, well-formed table parses identically in baseline and fixed builds (23/23 structural checks OK, including the state-entry callback path).

Fix A/B (same rig, same inputs, fix.diff applied to the same slice)

family baseline fixed
deep offsets (state/thermal/number) SIGSEGV +65281 rc=-1/-22, range-checked
fan V2 / PowerTune V3 / hard-limit tail SIGSEGV rc=-EINVAL/-1, full-struct range checks
count-255 copy loops SIGSEGV / byte-exact leak counts clamped to image (1/2/5), 0 leaked
od ACG [count-1] SIGSEGV +3298 / OOB decision bit clamped, decision bit in-image
pcie NULL sclk SIGSEGV addr 0 rc=-EINVAL (NULL guard)
vddc lookup write SIGSEGV obj+86 / 247 strided writes canary intact, count=8
dcefclk pioneer write SIGSEGV obj+232 / +6892 overwrite canary intact, loop=8
result clobber rc=0, NULL vddc table rc=1 propagated
entry off-by-one SIGSEGV image_end+12 rc=-1 (< + per-entry range check)
clean-valid OK identical

fix_status: fixed (baseline reproduced on the verbatim slice; patched slice clean on every mode; valid tables parse identically).

Hardware gating (unchanged from the pre-verification assessment)

In-kernel execution requires an AMD Vega10 ASIC: the parse runs at driver attach (ROM-provided table) or on root-written pp_table sysfs re-parse (amd_powerplay.c:671-706 β€” kmemdup + soft_pp_table swap + reset). This guest has no 0x1002 PCI device, no /dev/dri, no amdgpu module (env.txt), so the guest kernel never executes the path; reproduction is in the verbatim rig per the established evidence class for crafted-firmware parsers. There is no unprivileged userland trigger on stock hardware; the realistic vectors are a crafted/corrupt VBIOS (flashed ROM, vfio romfile, malicious device) or the root-gated sysfs blob.

Impact ceiling

Strongest proven primitive: attacker-controlled heap OOB write up to ~6.6 KB past a kmalloc-256 object (dcefclk pioneer) and a 2463-byte strided overwrite past a kmalloc-128 object (vddc lookup), both with byte-exact content control from the firmware image; plus a byte-exact kernel-heap info leak into sysfs-visible tables and several panic paths. Recorded impact "dos" follows the DF-4165 precedent for the identical evidence class and gating (heap OOB write proven in verbatim code, in-kernel execution ASIC-gated, no unprivileged trigger).

Corrections to the pre-verification pack (this run)

  • The verbatim rig supersedes the syntax-check + clamp-unit-test approach (vega10_clamp_test.c, vega10_processpptables_fixed.c removed).
  • The finding text calls the GFXCLK V2 record "12-byte"; the packed struct is 13 bytes (ulClk 4 + ucVddInd 1 + usCKSVOffsetandDisable 2 + usAVFSOffset 2 + ucACGEnable 1 + ucReserved[3] 3, vega10_pptable.h:147-154) β€” the rig measures and uses sizeof() throughout; no impact on any defect or fix.
  • fix.diff required NO corrections this run (applies fuzz=0, compiles clean, all modes fixed; contrast DF-4247 where the pre-verification fix had two compile bugs).

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

fixed
baseline reproduced→ patch + rebuild →patched clean

FIXED in the verbatim rig (same slice + fix.diff, identical inputs): all 16 baseline fault modes clean (offsets range-checked to soft_pp_table_size, counts clamped to image and destination, fan/PowerTune full-struct checks, pcie NULL guard, off-by-one '<' + per-entry range check, lookup failures propagated), both heap OOB writes gone (canaries intact, loops clamped to 8), all leaks gone (0 OOB records), and the fully valid table parses IDENTICALLY to baseline (23/23 structural checks) - no regression. In-kernel validation remains ASIC-gated on this guest (same as baseline).

run.log FIXED half (every mode vs baseline); build.log (fix.diff fuzz=0 forward-apply + byte-exact reverse-restore proof); rig/pp_slice_fixed.inc generation in rig/gen_rig.sh
↓ fix.diffper-fix-DF-4396

Confirmed kernel references

Detail

Exploit chain

crafted VBIOS PowerPlay table (ROM flash / vfio romfile / malicious device) or root pp_table sysfs blob -> vega10_pp_tables_initialize on Vega10 -> (a) u8-count heap OOB WRITE: vddc_lookup ucNumEntries=255 vs max_levels=8 overwrites 2463 bytes past a kmalloc-128 slab object with fully attacker-chosen u16 values (adjacent-object corruption); dcefclk pioneer count=255 overwrites ~6.6KB past a kmalloc-256 object -> memory corruption / code-exec potential on the ASIC; (b) count-driven OOB reads clone adjacent kernel heap into sysfs-visible DPM tables -> kernel-heap info leak; (c) u16 offsets -> deep OOB reads/NULL deref -> panic; (d) masked lookup failure -> NULL-table consumer crash. No unprivileged trigger on stock hardware.

Evidence (decisive lines)

run.log/run.2.log/run.3.log (3 stable runs, 16 FAULTs each, baseline vs fixed A/B); build.log (23/23 VERBATIM blocks identical on guest /usr/src/sys + fix.diff forward/reverse proof + cc build); leak_sample.txt (decisive leak/overwrite lines); env.txt (guest uname, no-AMD-GPU gate, host/guest parser sha256 equality); rig/ (full reproducible rig); fix.diff (validated artifact)

PoC changes

Replaced the pre-verification syntax-check + clamp-unit-test approach (vega10_clamp_test.c / vega10_processpptables_fixed.c, removed) with the full verbatim rig per the proven DF-4165/DF-4247 evidence class: machine-extracted parser slice + 22 header slices, guest-side verbatim checker, 23 crafted-table modes with guard/victim images and guard/canary destinations. Rig fixes during bring-up: unbuffered stdout so fault reports survive _exit; 22-page guard tail (a 1-page guard let the +0xFF00 reads land in adjacent heap mappings); pr_info / u8-u16 typedef / GetIndexIntoMasterDataTable shims; offsetof()-driven GFXCLK V2 ucACGEnable (+9, not +8) in the leak-expectation math.

Verified recommended fix

central vega10_pp_table_range_ok/vega10_pp_clamp_count/VEGA10_SUBTABLE_OK layer with destination-constant clamps (VDDC 8, VDDMEM/VDDCI 4, DCEFCLK NUM_DSPCLK_LEVELS), full-struct range checks for fan/PowerTune rev dispatch, pcie NULL guard, entry_index '<' fix, and result propagation in init_dpm_2_parameters (fix.diff, A/B-validated in the rig)

Verdict

REPRODUCED via the DF-4165/DF-4247 verbatim-rig evidence class: the ENTIRE production parser (vega10_processpptables.c:34-1326, checker-proven byte-identical ON THE GUEST against /usr/src/sys, the tree its running kernel was built from; 23/23 VERBATIM blocks, fix.diff forward/reverse proven) compiled into a harness and driven with crafted ATOM_Vega10 PowerPlay tables. Baseline: 16 SIGSEGVs at exactly the predicted sites across 3 runs (identical fault-offset fingerprints) - u16 subtable offsets dereferenced at image+65281 (check_powerplay_tables:82, get_number_of_entries:1249, init_thermal_controller:134), tail overreads at image_end+0..31 (count-255 copy loops for socclk/mclk/pixclk/mm/gfxclk V1, fan rev>10 V2 walk:214, PowerTune rev7 V3 overread:488, hard-limit entries[0]:814, od entries[254].ucACGEnable +3298:273), the get_pcie_table:781 NULL vdd_dep_on_sclk deref at addr 0x0 (DF-1587), and TWO HEAP OOB WRITES past kzalloc'd objects: get_vddc_lookup_table:1036 SIGSEGV at obj+86 of an 84-byte kmalloc-128 object with 247/247 OOB us_vdd writes byte-exact equal to the crafted image bytes (strided 2-byte overwrite to +2463, DF-1586), and the dcefclk pioneer path :740-748 SIGSEGV at obj+232 of a 228-byte kmalloc-256 object with a 1232-byte attacker-controlled overwrite reaching +6892. Leak legs byte-exact: 35/35 socclk and 38/38 GFXCLK V2-walk OOB records equal the bytes past the image (kernel-heap values surface to userland via powerplay sysfs), and the overdrive-limit engineClock decision bit provably comes from an OOB byte 490 bytes past the image. init_dpm_2_parameters:1103-1128 result-clobbering proven: parse returns rc=0 with NULL vddc_lookup_table (DF-3702 feeder). entry off-by-one :1308 ('<=') SIGSEGVs at image_end+12 (DF-1588). FIX A/B-VALIDATED in the same rig: fix.diff applied to the same slice - every crafted mode clean (range-checked offsets, clamped counts, NULL guard, '<' fix, propagated failures) and clean-valid parses IDENTICALLY (no regression). In-kernel execution AMD-ASIC-gated on this guest (no 0x1002 device, no /dev/dri, no amdgpu module - env.txt); threat model = crafted/corrupt VBIOS at driver attach or root-written pp_table sysfs re-parse; no unprivileged trigger on stock hardware. Impact 'dos' follows the DF-4165 precedent for the identical evidence class and gating (attacker-controlled heap OOB write proven in verbatim code, ASIC-gated in kernel).