# DF-4165 — VERDICT (verify run, 2026-10-14)

**Status: REPRODUCED (verbatim-rig evidence class). Memory corruption
confirmed in byte-identical production code; in-kernel execution is
AMD-ASIC-gated on this guest (no AMD GPU — proven, see env.txt). Fix A/B
validated in the same rig: fixed.**

## 1. What was verified and how

The guest cannot run the amdgpu/dc driver (Bochs SVGA 0x1234:1111 only,
`sysctl dev.drm` unknown, no drm/amdgpu KLDs — `env.txt`). Per the
established evidence class for crafted-firmware parsers, the **actual
production parser** was compiled into a guest-side harness:

- `rig/gen_rig.sh` sed-extracts the code byte-identical from the read-only
  `sys/` tree: `get_integrated_info_v11` (bios_parser2.c:1367-1578),
  `construct_integrated_info` (:1595-1643, revision dispatch),
  `bios_parser_create_integrated_info` (:1645-1664, the `kzalloc`),
  `get_atom_data_table_revision` (:133-151), `bios_get_image`
  (bios_parser_helper.c:36-44, the only bounds check on the path), plus every
  struct they touch (atomfirmware.h, grph_object_ctrl_defs.h,
  grph_object_id.h, bios_parser_types.h, bios_parser_types_internal2.h) and
  the exact `DATA_TABLES`/`GET_IMAGE` macros (bios_parser2.c:110,
  bios_parser_helper.h:39).
- `rig/check_verbatim.sh` re-proved all 21 blocks **byte-identical** — run
  both against the host `sys/` tree and **on the guest against `/usr/src/sys`,
  the tree its running kernel (Jul 2 2026 build) was compiled from**:
  `ALL VERBATIM CHECKS PASSED` (build.log). The only inserted lines anywhere
  are the 16 `#ifdef APPLY_DF4165_FIX` clamps, verified identical to
  `fix.diff`'s additions.
- Harness shims (rig_shims.h) touch nothing on the overflow path: minimized
  `dc_bios`/`bios_parser` (same member names, same first-member layout so
  `BP_FROM_DCB` container_of semantics hold), kzalloc→placement, LE-host
  `le*_to_cpu` identity, and a shim for `object_id_from_bios_object_id`
  (feeds only `device_connector_id`, never the retimer arrays).

The crafted image mimics a real ATOM ROM: master data table v2_1 at offset
0x20 with `integratedsysteminfo` pointing at a v1_11 table whose
`content_revision = 11` drives the production dispatch
(`construct_integrated_info` `switch (revision.minor) case 11:
get_integrated_info_v11`). Count bytes set per mode; the whole image is
attacker pattern data (a crafted ROM controls every byte).

## 2. Observed (run.log, stable across run.2.log)

Exact layout from the verbatim structs: `sizeof(struct integrated_info)`=692,
dest arrays at 582/601, 609/628, 636/655, 663/682, last member
`dp_ss_control`@688; source `atom_integrated_system_info_v1_11`=1140 B,
`atom_hdmi_retimer_redriver_set`=27 B (HdmiRegSetting@3 [9×2],
Hdmi6GhzRegSetting@21 [3×2]).

- **dest-guard** (kzalloc object ends exactly at a PROT_NONE page; all eight
  counts = 255): `SIGSEGV ... fault offset ... 692 (sizeof=692) -> 0 bytes
  PAST the allocation end => OUT-OF-BOUNDS WRITE` (rc=88). The first faulting
  write is the first byte past the 692-byte allocation — the production
  write loop walks straight off the object.
- **src-guard** (table ends at the mapped image end; destination kept in a
  huge writable mapping so only a source read can fault; only
  dp3.Hdmi6GRegNum=255): `SIGSEGV ... fault offset in BIOS image: 4096
  (bios_size=4096) => READ BEYOND BIOS IMAGE (OOB READ)` (rc=88). The loop
  indexed `Hdmi6GhzRegSetting[i]` past the [3]-entry array, past the whole
  1140-B table, and past the entire BIOS image.
- **canary** (dp0.HdmiRegNum=255 only; adjacent 512-B victim pre-filled
  0x41): 400/512 victim bytes changed, first changed byte at victim+0 =
  struct+692 = **the first byte past the object**, and **400/400 changed
  bytes equal the crafted-image byte at the exact source position**
  (0 mismatch). `dp_ss_control` overwritten with crafted bytes.
- **canary6g** (dp3.Hdmi6GRegNum=255 only): 500/512 victim bytes changed
  (write window 682..1191 → 500 bytes past the 692-B object), **500/500
  byte-exact** to the crafted image. In-kernel this kzalloc(692) lands in a
  kmalloc-1024 bucket: writes 1024..1191 (~168 B) reach the **adjacent slab
  object**; bytes 692..1023 corrupt the remainder of this slot. The copy is
  linear, sequential, no gaps, fully value- and length-controlled by image
  bytes (any count 10..255 → 2 to 500 bytes past the object).

## 3. Primitive and impact

Primitive: **linear, fully attacker-controlled kernel-heap overflow of up to
500 bytes past a kzalloc'd 692-B `struct integrated_info`** at driver
init-time (bios_parser2.c:1651 → :1989), plus OOB reads past the source ATOM
table (up to ~470 B past the 27-B retimer set; with a realistically sized
image the source reads stay inside the ROM buffer, so every written byte is
attacker-chosen). Gating: requires an AMD ASIC whose VBIOS carries
integratedsysteminfo v1_11 with out-of-bounds count bytes — i.e. crafted /
corrupted GPU firmware (flashed ROM, vfio-pci romfile override, malicious
device). **No unprivileged userland trigger exists** on stock hardware: the
counts come from the GPU ROM image, copied to kernel memory at driver attach.

In-kernel ceiling: adjacent-object corruption at module/driver
initialization → allocator panic (DoS floor) with potential for more given
the fully controlled content; under the finding's hardware/firmware attacker
model this is a code-execution-class primitive. Demonstrated on this guest
out-of-kernel-context (rig); impact recorded as `dos` (crash-class floor),
not `panic` (the guest kernel never executed the path).

## 4. Fix validation (A/B, identical crafted image)

`rig_fixed` = same verbatim slice + exactly the 16 clamp lines of
`fix.diff` (checker-verified equal to fix.diff additions) under
`-DAPPLY_DF4165_FIX`:

- dest-guard / src-guard: **no fault**, rc=0, all four retimer blocks
  clamped (`dp0=9/3 dp1=9/3 dp2=9/3 dp3=9/3`);
- canary / canary6g: **0/512 victim bytes changed**, `victim intact`,
  counts stored as 9 and 3.

Baseline corrupts, patched slice is clean on the same input → fix validated
(`fix_validation.log`). A rebuilt-kernel validation was not performed: the
fix site executes in-kernel only on AMD ASICs absent from this guest (per
the verbatim-rig protocol the fixed slice was A/B-validated in the same
rig). `fix.diff` remains authored against the pristine read-only `sys/`
tree and was never applied there.

## 5. Honest limitations

- The overflow is demonstrated with production instructions and production
  struct layouts, but in a userland mapping, not the kernel's kmalloc-1024
  slab. The allocator-adjacency arithmetic (slot end 1024, ~168 B into the
  neighbor) is derived from DragonFly kmalloc bucketing, not measured in
  kernel.
- The crafted image is synthetic (master table + v1_11 table only); a real
  crafted ROM must also satisfy earlier parser stages (ROM header, object
  tables) before `bios_parser_create_integrated_info` runs — those stages
  precede and do not constrain the retimer counts.
- `bios_get_image`'s `offset + size < bios_size` check bounds only the START
  of the v1_11 table (verified in-rig: a table at image end passes the check
  and still faults mid-loop), matching production behavior.

## 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.
