# DF-2808 — Cross-segment mapsize under-sizing → file-controlled kernel heap overflow in link_elf_load_file

## Build
```
python3 gen_exec_ko.py seg-overflow.ko seg-overflow
```
(host-side; no guest toolchain needed. Produces a 4.2 MB ET_EXEC x86-64 module.)

## Run
```
scp -F dfbsd-qemu/config seg-overflow.ko dfbsd:/tmp/
dfbsd-qemu/vm.sh run_root 'kldload /tmp/seg-overflow.ko; echo RC=$?'
dfbsd-qemu/vm.sh log 30     # panic signature
```

## Expected (stock kernel, verified 2026-09-01)
```
Fatal trap 12: page fault while in kernel mode
fault code       = supervisor write data, page not present
Stopped at      memmove+0x10a:  repe movsq (%rsi),%es:(%rdi)
```
Guest panics (write fault inside the vn_rdwr/uiomove copy). Before the fault,
~64 KB of adjacent kernel heap has already been overwritten with 0x41 bytes
read from the module file.

## Expected (patched kernel, fix.diff applied)
```
kldload: Segment ... error, RC != 0, guest stays up
```
(specifically "kldload: Overlapping or out-of-order segments" + ENOEXEC)

## Why (root cause, sys/kern/link_elf.c)
`link_elf_load_file` sizes the module mapping ONLY from the first segment's
start and the SECOND segment's end:

```c
541:  base_vaddr  = trunc_page(segs[0]->p_vaddr);
542:  base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz);
543:  mapsize     = base_vlimit - base_vaddr;
546:  ef->address = kmalloc(mapsize, M_LINKER, M_WAITOK);
553:  segbase     = mapbase + segs[i]->p_vaddr - base_vaddr;
554:  vn_rdwr(UIO_READ, vp, segbase, segs[i]->p_filesz, ...)
```

`segs[0]`'s own extent (`p_vaddr + p_memsz`, and `p_filesz`) is never required
to fit inside `mapsize`, and the "text then data, in that order" assumption
(line 497 comment) is never enforced. The trigger module uses

```
segs[0]: p_vaddr=0,      p_filesz=p_memsz=0x400000  (4 MB of 'A')
segs[1]: p_vaddr=0x100,  p_filesz=p_memsz=0x100
=> mapsize = round_page(0x200) - 0 = 0x1000 (one page)
=> vn_rdwr writes 4 MB of file-controlled bytes into the 1-page kmalloc
```

Even with `p_filesz <= p_memsz` in BOTH segments (so DF-0056's check-site is
not involved), the read overruns the allocation. Out-of-order segments
(seg1 below seg0) underflow `mapsize` to ~2^64; `p_vaddr + p_memsz` wrapping
2^64 shrinks `base_vlimit` — same unvalidated-arithmetic family, all fixed by
the segment-layout validation in `fix.diff`.

Threat model: kldload requires root (SYSCAP_NOKLD) — root-supplied-input
class, consistent with DF-0056 (Medium). The primitive is a deterministic,
fully file-controlled heap overflow (write-what-where contiguous) in the
kernel M_LINKER heap.
