# DF-2230 — Verification evidence pack

**Finding:** Kernel plist integer parsing silently saturates decimal values
exceeding INT64_MAX (unsigned fallback is dead code)
**File:** `sys/libprop/prop_number.c:519-584` — severity Medium, bucket base:libs
**Verdict:** **reproduced** on the stock kernel (wrong value + wrong signedness
stored; kernel/userland desync); fix validated (fixed kernel matches userland).

## What is in here

| file | role |
|---|---|
| `kernel_side.c` + `Makefile` | KLD that drives the REAL in-kernel parser path (`prop_array_internalize` -> `_prop_number_internalize` -> `_prop_number_internalize_signed` -> `strtoq`) with a case matrix of `<integer>` payloads and reports stored value + `pnv_is_unsigned` via the real accessors. No code copied from prop_number.c. |
| `userland_full.c` | same matrix through userland `prop_array_internalize` (stock `-lprop`, built from the same `sys/libprop` source) — the desync counterpart. |
| `userland_unit.c` | `#include` of the audited `prop_number.c` compiled in USERLAND mode (stock libprop flags) so the static parsers are callable directly; shows `errno=ERANGE (34)` and `rv=0` exactly where the kernel accepts. |
| `build.sh` | guest-side build; sha256-gates `guest /usr/src/sys/libprop/prop_number.c` == audited tree (`89da58da…`). |
| `run.sh` | guest-side baseline run (KLD load + both userland binaries). |
| `build.log` | full untrimmed baseline build output. |
| `run.log` | full untrimmed BASELINE run (stock kernel #0, Jul 2 2026) — the bug. |
| `fix.diff` | git-applyable one-hunk fix for `_prop_number_internalize_signed`. |
| `fix_build.log` | full untrimmed fixed-kernel build (`make nativekernel` + `installkernel`). |
| `fix_run.log` / `run.fixed.log` | identical matrix on the FIXED kernel (#1, Oct 17 2026). |
| `env.txt` | guest uname, compiler, kldstat. |
| `VERDICT.md` | full narrative + case-matrix tables + privesc assessment. |
| `manifest.json` / `verdict.json` | machine-readable catalog / persisted verdict. |

## How to reproduce (on the dfbsd QEMU guest, as root)

```
# copy this directory to the guest as /root/df2230, then:
sh /root/df2230/build.sh     # sha256 gate + build df2230.ko + 2 userland binaries
sh /root/df2230/run.sh       # baseline matrix (stock kernel)
```

For fix validation (what was done here):

```
cd /usr/src && patch -p1 < /root/df2230/fix.diff
make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC
reboot                                       # into fixed kernel
sh /root/df2230/run.sh                       # fixed matrix
```

## Expected decisive output (baseline, stock kernel)

Kernel column shows the bug — decimal inputs in (INT64_MAX, UINT64_MAX]
stored as **signed INT64_MAX with `is_unsigned=0`**:

```
DF2230|K|in=9223372036854775808|…|is_unsigned=0|signed=9223372036854775807 (0x7fffffffffffffff)|…
DF2230|K|in=10000000000000000000|…|is_unsigned=0|signed=9223372036854775807 (0x7fffffffffffffff)|…
DF2230|K|in=18446744073709551615|…|is_unsigned=0|signed=9223372036854775807 (0x7fffffffffffffff)|…
DF2230|K|in=0xffffffffffffffff|…|is_unsigned=1|…unsigned=18446744073709551615…   # hex correct
```

while the userland build of the SAME source gives:

```
DF2230|U|in=9223372036854775808|…|is_unsigned=1|…unsigned=9223372036854775808 (0x8000000000000000)|…
DF2230|UU|in=9223372036854775808|signed_rv=0|errno=34|…      # ERANGE check is live in userland
```

On the FIXED kernel, every case in (INT64_MAX, UINT64_MAX] returns the correct
unsigned value and `-9223372036854775809` is rejected — byte-identical to the
userland column; boundary/negative/small/hex cases unchanged from baseline.
