# DF-5051 — VERDICT

**Finding**: `dal_vector_insert_at()` performs no bounds check on `position`
(vector.c:204-234). `insert_address = container + struct_size * position`
(vector.c:218) is computed from the raw caller value and written to
unconditionally (vector.c:226-229, `memmove(insert_address, what, struct_size)`).
The header (include/vector.h:69-71) documents the check as the caller's job
("do not check that index belongs to container since the function is private"),
but the function is a plain exported symbol of the DC library.

**Source analysis** (pass 2): the only in-tree caller that passes a non-`count`
index does not exist — `dal_vector_append` (vector.c:236-241) passes `count`;
the sole consumer of the entire dal_vector API in the tree is
`dc/core/dc_link_ddc.c` (construct/append/destruct only, EDID/DDC payloads
bounded by `write_size/read_size <= EDID_SEGMENT_SIZE`, dc_link_ddc.c:573).
So the OOB write is a **latent library defect**: any future/other caller that
computes an index one element past `count` (the header itself suggests
"get_count+1" as a legitimate caller pattern — which is ALREADY off-by-one:
`count+1 > count`) gets a heap write at a chosen offset.

**Runtime verification** (QEMU guest, DragonFly 6.5-DEV #0 Jul 2 2026,
kernel `X86_64_GENERIC`, no AMD GPU present — amdgpu.ko loaded as a module):

- Built a root-owned arbitrary-kernel-call facility (`kv.c`, see README) because
  freshly-linked kmods GPF on this snapshot during `module_register`
  (`strcmp` on garbage `moduledata.name` — a toolchain/linker incompatibility
  of the snapshot, root-only impact, out of audit scope; documented in the
  pack as `NOTES-module-loader.txt` content in this file).
- Called the REAL `dal_vector_create` from amdgpu.ko: returned a valid vector;
  bcopy-read its fields: `container=0xfffff8008f9a4cc0, struct_size=16,
  count=0, capacity=4` — exactly the struct from include/vector.h:29-35.
- Called the REAL `dal_vector_insert_at(v, version, 0x0C000000)`:

```
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0xfffff8014db44340
fault code            = supervisor write data, page not present
instruction pointer   = 0x8:0xffffffff80bca976
Stopped at memmove+0x76: movq %rdx,(%rdi)
```

`0xfffff8014db44340 = container(0xfffff8018db44340) + 16*0x0C000000` — a
**supervisor WRITE** at the exact predicted offset, in the exact predicted
memmove. Three independent reproductions across boots (one with `position=5`,
fault at `container+0x50`: `0xfffff801d6fa5880`; one with `0x0C000000`).

**Primitive characterization**: 16-byte write (attacker-of-the-caller chosen
content, e.g. any kernel-readable 16 bytes) at `container +
(uint32)(struct_size * position)` — any 16-byte-aligned offset within ±4GB of
the chunk (32-bit multiply can also wrap the offset). In the shipped DC code
no unprivileged path controls `position`, so this is a library-primitive
demonstration, not a direct privesc: exploitation requires a misusing caller,
none exists in-tree today. Severity Low (latent), consistent with the pass-1
treatment of DF-2068 (same file, same latent class).

**Why not uid=0**: the primary-success criterion (unpriv → uid=0) does not
apply: reaching the sink requires kernel code to pass a bad index; the only
in-tree index is `count` (append). The primitive is proven; the missing
ingredient is a caller bug, which is what the fix eliminates.

**Fix validation**: `fix.diff` (bounds check + header doc fix) applies cleanly
to `sys/`. A full fixed-module rebuild could not be exercised on this guest
(freshly-linked kmods crash at load — snapshot toolchain issue, see above;
hot-patching module text via /dev/kmem was attempted and the writes were
accepted, but every attempt to execute the patched path was cut short by the
guest's session instability after repeated kmem calls). Fix status for this
finding: `not_testable` at runtime on this harness; the change is 4 lines with
trivially auditable semantics (`if (position > vector->count) return false`),
and the DF-5052 companion fix's semantics WERE runtime-validated (see that
pack). fix.diff was authored after verification against the exact disassembly
of the running kernel (`insert_at+0x14` reads `count` at offset 0xC; the fix
inserts the guard before the first dereference).

**Artifacts**: `panic-baseline-oobwrite.log` (decisive panic),
`supplementary-run6-insertat-count-read.log` (same-boot evidence of executing
`insert_at+0x14` reading `vector->count` at 0xffffffff8f9a4d4c),
`kv.c` (call facility), `run-baseline.sh`, `gen_run.py`, `mkpatch.c`,
`vectorpoc.c` (the kmod PoC that could not be loaded on this snapshot — kept
for guests with a working module loader), `fix.diff`.

**Environment notes** (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`
QEMU/KVM, 4 GB, 6 vCPU, no SMAP/SMEP/KASLR. Guest left clean (with-src
snapshot) after the run.

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