# DF-5632 VERDICT — REPRODUCED (OOB kernel write via ABI-skewed bus_add_child), fix validated

## Root cause (path:line)

`iicbus_add_child` (`sys/bus/iicbus/iicbus.c:57,164-171`) is declared and
registered (`DEVMETHOD(bus_add_child, iicbus_add_child)`, `iicbus.c:66`)
with a FreeBSD-legacy **4-argument, `int`-returning** prototype. DragonFly's
`bus_add_child` interface (`sys/kern/bus_if.m:128-134`) is **5-argument,
`device_t`-returning** (`bus`, `parent`, `order`, `name`, `unit`).
`DEVMETHOD` performs no signature check (`sys/sys/bus.h`), so every dispatch
through the iicbus driver skews the arguments:

* `order` ← the `parent` device_t (truncated),
* `name` ← the integer `order` (0 → NULL),
* `unit` ← the `name` string-literal address (truncated, negative),
* return value `0` → `NULL` for every caller expecting the new child
  (`iic.c:109`, `iicsmb.c:141`, `iicbus.c`'s own callers-to-be).

The skewed `device_add_child_ordered(dev, order, name, unit)` creates a
**classless child with a negative wired unit**. The first probe of that
child (from `iicbus_add_child`'s own `bus_generic_attach(dev)`, or the
`bus_generic_driver_added` probe loop) reaches
`devclass_add_device` → `devclass_alloc_unit`, where a negative wired unit
skips both the collision check and the table extension
(`sys/kern/subr_bus.c`, `devclass_alloc_unit`), and then

```c
dc->devices[dev->unit] = dev;    /* devclass_add_device */
```

writes an 8-byte kernel heap pointer **out of bounds, below the devclass
device array**.

## Evidence (guest, DragonFly 6.5-DEVELOPMENT, stock /boot/kernel/iicbus.ko)

* `panic_skew_stock.txt` — trigger 1 (module load): rig's `df5632k` driver
  uses the verbatim `iic_identify` pattern (`iic.c:104-110`); its
  registration on the attached iicbus0 fires `BUS_ADD_CHILD` →
  `Fatal trap 12`, `supervisor write data, page not present`,
  `fault virtual address = 0xfffffffc131cb558`,
  `Stopped at devclass_add_device+0xf6: movq %r14,(%rdx,%rax,1)`,
  current process = `kldload`. Full chain on serial console:
  fakebb0 → iicbb0 → iicbus0 (attached, trio created) → rig attach done →
  panic at df5632k driver registration.
* `panic_skew_addchild.txt` — trigger 2 (API contract): bus verified healthy
  (`STAT: nchildren=3`, iicbus0 attached `state=3`), then ONE
  `BUS_ADD_CHILD(iicbus0, iicbus0, 0, "df5632c", -1)` (what every identify
  method does) → identical `Fatal trap 12` at `devclass_add_device+0xf6`,
  `fault virtual address = 0xfffffffc131cc228`, current process = `dfctl`.
* Fault VAs (0xfffffffc…) = `dc->devices + 8*(negative int)` — the
  negative-index arithmetic exactly as derived from the skew.

Reachability honesty: the trigger is `kldload` of an iicbus client driver
(root-gated), which is why this is Medium and not High. In-tree `iic.ko` and
`iicsmb.ko` escape only because `iicbus_attach` pre-creates their rendezvous
children, so their identify guards never call `BUS_ADD_CHILD` on an iicbus.
Any out-of-tree or future in-tree client following the documented pattern
(`sys/kern/device_if.m:99-101`: "Using generic_bus_identify() will simply
call BUS_ADD_CHILD using the driver name") takes the OOB write at load.

## Fix validation (fix.diff, module-only rebuild of iicbus.ko)

`run_d_fixed.log` / `run_d_fixed_dmesg.txt`:

* `dfctl addchild` → `BUS_ADD_CHILD` returned **0xfffff801175bc9c0** (real
  device_t, not NULL) and `child[3] devclass=df5632c unit=0 driver=(none)`
  — the rendezvous is created with the requested name/unit;
* no panic at load, under addchild, under 2 detach/reattach cycles, or at
  unload (`RUN-D-DONE`, guest healthy).

## Distinction from the family findings

* DF-5559 (iic.c) is the *consumer* of the missing ivar plumbing; this
  finding is the *provider-side* ABI break. Its fix (read/write_ivar) does
  not touch `bus_add_child`.
* DF-5563 (iiconf.c) is the waiter/teardown protocol; unrelated to
  add_child.
* DF-5633 (same file) is attach-time child duplication; DF-5634 is the ivar
  allocation; DF-5635 is detach error propagation. One coherent fix.diff
  covers all four (each is independently validated).

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