# DF-2746 — sys_mincore() off-by-one write below the user `vec` pointer

DragonFlyBSD `sys/vm/vm_mmap.c`, `sys_mincore()`.

## Bug

The byte-vector maintenance loops use `lastvecindex = -1` as "nothing
written yet" but then write at `vec + lastvecindex` (i.e. `vec[-1]`) on
the first iteration instead of `vec + lastvecindex + 1`:

* gap-fill loop — `sys/vm/vm_mmap.c:920-927`
* tail-fill loop — `sys/vm/vm_mmap.c:961-968`

Whenever the first page the kernel reports on is not page 0 of the
scanned range (leading unmapped page(s)), the kernel stores one NUL byte
at `vec[-1]` — one byte *below* the pointer the user supplied — before
writing `vec[0]`. Additionally `vecindex`/`lastvecindex` are `int` while
`OFF_TO_IDX()` yields a 64-bit page count, so ranges ≥ 2^31 pages
(≥ 8 TiB) truncate the index (writes redirected by ±2 GiB; still
confined to user space).

Impact boundary: `std_subyte` rejects addresses ≥ `VM_MAX_USER_ADDRESS`
(`sys/platform/pc64/x86_64/support.s:632-634`), so writes stay inside the
caller's own user address space and the written value is always 0 (or a
MINCORE_* nibble). No privilege boundary is crossed ⇒ severity Low
(POSIX contract violation + single-byte corruption of adjacent user
memory chosen by the caller's `vec` placement; classic heap-metadata
neighbor corruption in the calling process).

## Build

    cc -O -o /tmp/mincore_oob mincore_oob.c

## Run (unprivileged)

    /tmp/mincore_oob

## Expected output on a vulnerable kernel

    DF-2746 mincore(vec) off-by-one probe
    test1 (all-unmapped range, tail-fill loop):
      vec[-1] = 0x00  (must still be 0x5A)
      vec[0]  = 0x00  (0x00 ok: page unmapped)
      => VULNERABLE: kernel wrote NUL at vec[-1]
    test2 (leading hole, gap-fill loop):
      ... same ...
    RESULT: VULNERABLE (2)

Exit code 0 + `RESULT: VULNERABLE` = bug present.
On a fixed kernel both sentinels stay `0x5A`, `RESULT: not vulnerable`,
exit code 2.

## Fix

`fix.diff` (4 hunks): write at `vec + lastvecindex + 1` in both loops and
widen the indices to `vm_pindex_t`. Validated by kernel rebuild in the
QEMU guest — see VERDICT.md.
