# DF-4167 — VERDICT (verify run, 2026-10-15)

**Status: REPRODUCED (verbatim-rig evidence class). The parser accepts a
zero reference clock with BP_RESULT_OK on both claimed triggers, and the
production PLL math divides by that zero at the exact cited line
(dce_clock_source.c:145) — SIGFPE/FPE_INTDIV with RIP inside the cited
function, on the guest, in code byte-identical to the running kernel's
source. 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

Same evidence class as DF-4165 (this file's sibling): the guest cannot run
amdgpu/dc (Bochs SVGA 0x1234:1111 only, `sysctl dev.drm` unknown, no
drm/amdgpu KLDs — `env.txt`), so the **actual production code** was compiled
into a guest-side harness:

- `rig/gen_rig.sh` sed-extracts, byte-identical from the read-only `sys/`
  tree: `get_atom_data_table_revision` (bios_parser2.c:133-151),
  `bios_parser_get_firmware_info` (:1119-1155, revision dispatch),
  `get_firmware_info_v3_1` (:1157-1202, control), `get_firmware_info_v3_2`
  (:1204-1280, the defect), `bios_get_image` (bios_parser_helper.c:36-44),
  and the full production PLL sink chain from dce_clock_source.c:
  `calculate_fb_and_fractional_fb_divider` (:130-170),
  `calc_fb_divider_checking_tolerance` (:189-243),
  `calc_pll_dividers_in_range` (:245-285),
  `calculate_pixel_clock_pll_dividers` (:287-388), and
  `calc_pll_max_vco_construct` (:1142-1218) — plus every struct they touch
  (atomfirmware.h tables verbatim under the production `#pragma pack(1)`
  at :207/:2934, grph_object_ctrl_defs.h `dc_firmware_info`,
  clock_source.h `pll_settings`/`calc_pll_clock_source*`, the exact
  `DATA_TABLES`/`GET_IMAGE` macros).
- `rig/check_verbatim.sh` re-proved all 34 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 checker
  additionally **applies fix.diff to the production function** and proves
  the `APPLY_DF4167_FIX` variant compiled into `rig_fixed` is exactly that
  patch result (87 lines, `OK … == fix.diff applied to
  bios_parser2.c:1204-1280`).
- Harness shims (rig_shims.h) touch nothing on the verified path: minimized
  `dc_bios`/`bios_parser` (first-member layout, container_of identity),
  `div_u64`/`div_u64_rem` = plain 64-bit hardware division (exactly what
  x86-64 kernels compile these to — including the divide-by-zero fault:
  kernel #DE ↔ userland SIGFPE/FPE_INTDIV), `DC_LOG_ERROR` log-only,
  kzalloc→placement, LE-host `le*_to_cpu` identity.

The crafted image is a minimal ATOM ROM: master data table v2_1 @0x20 with
firmwareinfo v3.2 (format_revision 3, content_revision 2) @0x100 driving the
production dispatch (`switch (revision.major) case 3: minor 2 → v3_2`),
dce_info v4_1 @0x200 with `dce_refclk_10khz = 0`, and — per mode — smu_info
missing (master-table offset 0) or present with content_revision 1/2/3.

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

### Parser level — the defect, exactly as filed

- **fw-v32-nosmu** (smu_info table MISSING): the missing-table path proven —
  `GET_IMAGE(header, DATA_TABLES(smu_info)==0)` passes (`0+4 < bios_size`)
  and returns the **image base**, whose bytes become the "table header":
  revision parsed as major = bios[2]&0x3f = 16, minor = bios[3]&0x3f = 32 —
  neither 2 nor 3 → fallback skipped → **`BP_RESULT_OK` with
  `pll_info.crystal_frequency = 0`**. (The filed summary's byte arithmetic
  "minor=0x2A from 0x55 0xAA" is off in which byte lands in minor — the
  u16 structuresize eats bytes 0-1, minor comes from byte 3 — but the
  substance is identical: a missing table parses garbage that is not 2/3.)
- **fw-v32-smu1** (smu_info present, revision.minor = 1): fallback skipped
  → **OK + 0** — the "any other smu revision" trigger.
- Controls: smu revision 2 → 27000, revision 3 → 100000 (the conditional
  fallback works when the revision matches); **v3.1 firmwareinfo with zero
  refclk → 27000 unconditionally** (bios_parser2.c:1187-1188) — the exact
  contrast that isolates v3_2 as the gap.

### Sink level — the #DE, at the cited line

- **sink-ssdp-post-smu1** (full production chain: parser →
  `calc_pll_max_vco_construct` stores `ref_freq_khz = 0` at
  dce_clock_source.c:1159 → first mode set on the SS/DP path where the VBIOS
  AdjustPixelClock exec table has filled **both** `reference_divider` and
  `pix_clk_post_divider` (dce_clock_source.c:447-450)):
  **`SIGFPE si_code=2 (FPE_INTDIV)`, RIP inside
  `calculate_fb_and_fractional_fb_divider`** (range proven via printed
  function bounds). On that path every other divisor is a compile-time or
  struct non-zero (fract factor 10^6, precision factor, post_div ≥ 1,
  ref_div = 1, constants); the only zero divisor is
  `calc_pll_cs->ref_freq_khz` at **dce_clock_source.c:145**
  `div_u64(feedback_divider, calc_pll_cs->ref_freq_khz)` — kernel
  equivalent: **#DE → kernel panic** on the first mode set.
- Why both VBIOS-adjusted dividers are needed (traced in production source):
  with only `reference_divider` preset, v3_2's entirely-zero-filled
  `pll_info` (min/max output VCO = 0) makes `max_post_divider = 0` and the
  function exits gracefully at the "Post divider range is invalid" check
  (dce_clock_source.c:358-362) before dividing (mode `sink-ssdp-smu1`:
  rc=0). With `pix_clk_post_divider` also preset (:304-306) the range
  check is bypassed exactly as in production and the `:145` division runs.
- **sink-plain-smu1** (no VBIOS-adjusted dividers — plain mode set):
  `SIGFPE` inside `calculate_pixel_clock_pll_dividers` — 0/0 at
  **:336-337** (`ref_freq_khz / max_pll_input_freq_khz`, both zero).
  Incidental and pre-existing: the *divisor* there is zero because v3.x
  never fills `pll_info.min/max_input_pxl_clk_pll_frequency` at all —
  v3_1 is equally affected (the fixed build still faults here with
  27000/0). Recorded as an observation, NOT DF-4167's gap.

## 3. Primitive and impact

Primitive: **crafted-VBIOS-controlled kernel divide-by-zero (#DE panic) at
first mode set**, driver-init→modeset timeframe. Gating: requires an AMD
ASIC whose VBIOS carries firmwareinfo v3.2/v3.3 with `dce_refclk_10khz = 0`
and a missing/mismatched smu_info revision — i.e. crafted or corrupted GPU
firmware (flashed ROM, vfio-pci romfile override, malicious device). No
unprivileged userland trigger exists (the values come from the GPU ROM
copied to kernel memory at attach).

In-kernel reachability of the *faulting* sink, traced precisely:
`calc_pll_max_vco_construct` is called only by `dce110_clk_src_construct`
(dce_clock_source.c:1220), used by **dce80/dce100/dce110** clock sources —
while `dal_bios_parser_create` (bios_parser_interface.c:41) tries
`firmware_parser_create` (bios_parser2) **first for every ASIC**, and the
v3_x dispatch is purely table-revision driven. A crafted new-format ROM on
those ASICs therefore reaches `get_firmware_info_v3_2` → zero clock → #DE.
Genuine DCE11x/DCE12/DCN10 clock sources use `dce112_clk_src_construct`
(:1323) which never runs the calc-PLL math; there the zero flows into
`dce_i2c_hw` reference clock (dce_i2c_hw.c:108) and
`res_pool->ref_clock_inKhz` (dc_resource.c:162) as misconfiguration (no
division), and DDC timing silently breaks. The finding's intermediate chain
("dce120_clock_source_create → dce112_clk_src_construct →
calc_pll_max_vco_construct") is off on the middle hop (dce112's construct
does not call calc_pll_max_vco_construct in this tree) — the sink is
reached via the dce110-family construct; the defect and the crash are
unaffected.

Impact recorded as `dos` (crash-class floor demonstrated in the rig; the
guest kernel never executed the path).

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

`rig_fixed` = same verbatim slice + exactly fix.diff (checker-proven equal
to the patch applied to production) under `-DAPPLY_DF4167_FIX`:

- fw-v32-nosmu → `BP_RESULT_BADBIOSTABLE` (require-table check); the bad
  table no longer yields an OK result.
- fw-v32-smu1 → OK with **27000** (unconditional fallback).
- sink-ssdp-post-smu1 → `ref_freq_khz = 27000`, the full divider search
  completes (`feedback_divider=11, fract=407407, post_div=2, vco=307998`),
  **no fault**.
- sink-plain-smu1 → still faults at :336 with 27000/0 (pre-existing
  v3_1-equivalent unfilled-pll_info issue; out of scope for this fix — see
  notes; the fix's require-table path would also reject a fully-missing
  table before this could matter).

Baseline faults, patched slice computes on the same input → **fix
validated** (`run.log` FIXED sections). 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

- Demonstrated with production instructions and production struct layouts,
  but in a userland mapping, not the kernel's text/heap; #DE ↔ SIGFPE is
  the standard equivalence for this rig class.
- The `:145` sink requires the VBIOS AdjustPixelClock table to supply
  non-zero `reference_divider` + `pix_clk_post_divider` (realistic for
  SS/DP mode sets and attacker-controlled under the crafted-ROM model),
  because v3_2's zero-filled `pll_info` otherwise trips the graceful
  post-divider-range error first.
- The `:336` 0/0 fires even without those, but its decisive zero is the
  unfilled input-frequency field (pre-existing, v3_1-equivalent), not the
  crystal_frequency gap this finding is about.
- The crafted image is synthetic (ROM header + master table + the three
  tables); a real crafted ROM must also satisfy earlier parser stages,
  which do not constrain these fields.

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