# DF-4787 VERDICT

* **Status:** untested (hardware-gated)
* **Confidence:** certain (code-path analysis)
* **Severity filed:** Low (CWE-476 NULL pointer dereference)

## Root cause — line-accurate trace

1. `gpio_service.c:224` `dal_gpio_service_open(service, id, en, mode, &pin)`.
2. `gpio_service.c:245-247` (DDC_DATA), `:250-252` (DDC_CLOCK), `:258-261` (HPD):
   the just-returned `pin` from `create_ddc_data()` / `create_ddc_clock()` /
   `create_hpd()` is passed straight into `define_ddc_registers(pin, en)` /
   `define_hpd_registers(pin, en)`.
3. The `if (!pin)` guard only runs at `gpio_service.c:276` — **after** the dereference.
4. `dce110/hw_factory_dce110.c:110-116`:
   ```c
   struct hw_ddc *ddc = HW_DDC_FROM_BASE(pin);
   switch (pin->id) {          /* NULL + offsetof(struct hw_gpio_pin, id) → fault */
   ```
   `dce110/hw_factory_dce110.c:135-139`:
   ```c
   struct hw_hpd *hpd = HW_HPD_FROM_BASE(pin);   /* container_of(NULL,…) ≈ 0x…   */
   hpd->regs = &hpd_regs[en];                    /* WRITE to near-NULL → fault  */
   ```
   Same shape in dce80 (`hw_factory_dce80.c:114-120`), dce120 (`hw_factory_dce120.c:129-135`,
   `:154-158`), dcn10 (`hw_factory_dcn10.c:124-130`, `:149-157`).
5. Producers of NULL: `hw_ddc.c:224-227` (`kzalloc` failure), `hw_ddc.c:219-222`
   (`en` outside `[GPIO_DDC_LINE_MIN..MAX]`), `hw_hpd.c:149-152`, `hw_hpd.c:153-160`
   (`kzalloc` failure / `en` outside `[GPIO_HPD_MIN..MAX]`, `id != GPIO_ID_HPD`).

## Why it is only Low

* The `en`-out-of-range arm is unreachable today: every caller obtains `en` from
  `translate.funcs->offset_to_id()` (bounded mask switches, e.g.
  `dce110/hw_translate_dce110.c:41-101`) or from compile-time enums; a VBIOS GPIO record
  with an unknown offset/mask is rejected (`offset_to_id` returns false →
  `dal_gpio_create_ddc` / `dal_gpio_service_create_irq` return NULL before reaching open).
* The remaining trigger is kernel heap exhaustion during a DDC/HPD pin creation
  (`kzalloc(sizeof(struct hw_ddc/hpd))` fails). The result is a NULL-page
  read/write — a clean panic, not a controllable primitive.

## Why untested on this run

The single-tenant QEMU guest is `DragonFly dfbsd 6.5-DEVELOPMENT` on KVM/q35 with only
virtio + Intel devices (`env.txt`: `pciconf -l` — no vendor 0x1002 display device, no
vendor 0x1000 MPT3 device; no drm/amdgpu module loaded). The DC GPIO service cannot be
instantiated without AMD display hardware, so neither baseline nor fault-injected
reproduction is possible. `fix.diff` was therefore not boot-validated either; it is a
mechanical reorder + NULL-guard whose worst-case behavior is strictly narrower than the
original (no new dereference sites introduced).

## Recommended fix summary

Move `define_ddc_registers`/`define_hpd_registers` after the `!pin` check and reject
NULL `create_*` function pointers before calling them (fix.diff).

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