⬢ DragonFlyBSD Kernel Audit
DF-4165 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4165",
  "status": "reproduced",
  "verdict": "REPRODUCED via the verbatim-code rig: get_integrated_info_v11() (bios_parser2.c:1367-1578), its dispatch construct_integrated_info() (:1595) and the kzalloc(692) at :1651 were sed-extracted byte-identical from sys/ (21 blocks re-verified identical ON THE GUEST against /usr/src/sys, the tree its running kernel was built from) and driven with a crafted ATOM integratedsysteminfo v1_11 image (content_revision=11) whose retimer count bytes exceed the arrays. Baseline production code: dest-guard mode SIGSEGVs writing at exactly struct+692 = the first byte past the kzallocd 692-byte struct integrated_info (OUT-OF-BOUNDS WRITE); src-guard mode SIGSEGVs reading image offset 4096 with bios_size=4096 (Hdmi6GhzRegSetting[i] indexed past the [3] array, past the 1140-byte table, past the whole BIOS image - OOB READ); canary modes show a linear, fully attacker-controlled overwrite of 400 (dp0.HdmiRegNum=255) and 500 (dp3.Hdmi6GRegNum=255) bytes past the object, every changed byte byte-exact equal to the crafted-image byte at the corresponding source position (900/900, zero mismatches), including clobber of the last struct member dp_ss_control@688. In-kernel: kzalloc(692) lands in a kmalloc-1024 slot, so the 500-byte overflow runs ~168 bytes into the adjacent slab object. Gating: requires an AMD DCE12-class ASIC with crafted/corrupted VBIOS (flashed ROM, vfio romfile, malicious device) - the count fields are raw u8 image bytes from the GPU ROM copied to kernel memory at driver attach; there is NO unprivileged userland trigger, and this guest has no AMD GPU (Bochs 0x1234:1111 only, no dev.drm, no amdgpu - 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. fix.diff (clamp all eight counts to 9/3) A/B-validated in the same rig on the identical image: no faults, counts clamped 9/3, victim intact 0/512 changed.",
  "reproduced": true,
  "impact": "dos",
  "confidence": "certain",
  "exploit_chain": "Hardware/firmware attacker model only: craft VBIOS with integratedsysteminfo v1_11 (content_revision=11) and any dpN_retimer_set.HdmiRegNum>9 or Hdmi6GRegNum>3 -> amdgpu attach -> dc construct -> bios_parser2_construct (bios_parser2.c:1989) -> bios_parser_create_integrated_info kzalloc(692) (:1651) -> revision dispatch (:1615) -> get_integrated_info_v11 unclamped loops write 2*count bytes starting at dpN_ext_hdmi_reg_settings (offset 582/609/636/663) or dpN_ext_hdmi_6g_reg_settings (601/628/655/682) -> sequential attacker-value-controlled heap overflow up to 500 bytes past the object into the kmalloc-1024 neighbor (kernel impact floor: slab corruption/panic at driver init; content fully controlled). No unprivileged-user chain exists - counts come from GPU ROM, not syscalls.",
  "evidence": "run.log (all five modes, baseline vs fixed), run.2.log (stability), fix_validation.log (A/B extract), build.log (22x identical to production verbatim checks incl. guest /usr/src/sys + zero-warning build of both binaries), VERDICT.md (full narrative + limitations), rig/ (sources), env.txt (hardware gating), code_hashes.txt",
  "kernel_refs": [
    "sys/dev/drm/amd/display/dc/bios/bios_parser2.c:1441",
    "sys/dev/drm/amd/display/dc/bios/bios_parser2.c:1448",
    "sys/dev/drm/amd/display/dc/bios/bios_parser2.c:1489",
    "sys/dev/drm/amd/display/dc/bios/bios_parser2.c:1496",
    "sys/dev/drm/amd/display/dc/bios/bios_parser2.c:1615",
    "sys/dev/drm/amd/display/dc/bios/bios_parser2.c:1651",
    "sys/dev/drm/amd/display/dc/bios/bios_parser2.c:1989",
    "sys/dev/drm/amd/display/dc/bios/bios_parser_helper.c:38",
    "sys/dev/drm/amd/include/atomfirmware.h:1051",
    "sys/dev/drm/amd/display/include/grph_object_ctrl_defs.h:378"
  ],
  "poc_changes": "Seed pack had no runnable PoC (status untested, hardware-gated). Built the verbatim rig from scratch: gen_rig.sh extracts the production slice byte-identical; check_verbatim.sh proves block identity (host tree AND guest /usr/src/sys) and that the APPLY_DF4165_FIX lines are exactly fix.diffs additions; harness drives five modes with guard pages and a 0x41 canary victim; the crafted image includes the master-data-table indirection and the content_revision=11 dispatch so the production dispatch chain executes.",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026  root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "runtime_sec": 900,
  "guest_dirty": 0,
  "build_cmd": "cd /root/df4165/rig && sh ./build.sh /usr/src",
  "run_cmd": "cd /root/df4165/rig && sh ./run.sh",
  "code_hash": "retimer_rig.c 2282246c8ecbf57495905641ac3dc06d1a69d0b8ffeee7ee99ee5ec4ffc085db; bios_slice_verbatim.c 98caa2c7e6430df0f037631e83e80e9c73fe124f41794906982915e0fb7a7484 (full list in code_hashes.txt)",
  "notes": "Impact recorded as dos = crash-class floor of the demonstrated primitive (adjacent-slab corruption at driver init on the target hardware class); the content-controlled nature makes worse outcomes plausible under the crafted-firmware attacker model, but no kernel of this guest executed the path, so panic/privesc were not observed. bug reproduced deterministically twice (run.log, run.2.log). bios_get_images offset+size<bios_size check bounds only the table START (verified in-rig: table placed at image end passes the check and still faults mid-loop). Guest left up and clean: rig removed from /root after artifact retrieval.",
  "recommended_fix": "Clamp all eight retimer register counts to their destination array sizes (9 / 3) before the copy loops - fix.diff, A/B validated in the rig.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "A/B validated in the verbatim rig: identical crafted image, same slice, only the 16 clamp lines of fix.diff added (-DAPPLY_DF4165_FIX). Baseline: OOB-write fault at struct+692, OOB-read fault past the image, 400+500 victim bytes corrupted byte-exact. Fixed: every mode completes rc=0, no fault, stored counts clamped to 9 and 3, victim intact (0/512 changed). Kernel-rebuild validation not performed: the fix site executes in-kernel only on AMD ASICs, absent from this guest (no AMD GPU per env.txt); per the verbatim-rig protocol the fixed slice was validated in the same rig. fix.diff authored against the pristine read-only sys/ tree, never applied there.",
  "fix_evidence": "fix_validation.log (baseline vs fixed A/B extract); run.log FIXED sections; build.log (fix lines == fix.diff additions); fix.diff"
}