# DF-5679 — VERDICT (pass 2, GLM 5.3)

**Target:** `sys/libkern/icrc32.c` — CRC-32/CRC-32C data-integrity primitives.
**Mode:** audit pass 2 with self-verification. **Guest:** DragonFly 6.5-DEVELOPMENT
(#0 Thu Jul 2 2026, X86_64_GENERIC); `/usr/src/sys/libkern/icrc32.c` md5-identical
to the audited tree (`29e2ead0a146caec695a6804944e3cde`). All evidence in this
pack was produced on that guest with its own `cc 8.3`.

## Bottom line

The file's *arithmetic* is bit-exact and memory-safe; the only defect found is a
`size_t`→`unsigned int` length truncation in the public API
(`sys/libkern/icrc32.c:776-786` wrappers → `:760-770` implementation), **demonstrated
at runtime** (T10 / `fixdemo_baseline`), **unreachable by every in-tree caller
today** (bounds audit below), and **fixed and fix-validated** (`fix.diff` /
`fixdemo_patched`). Severity: Info (hardening / correctness-contract). Everything
else the checklist asked for was hunted and killed with machine-checked evidence.

## What was verified and how

### (a) Tables / polynomial constants — VERIFIED ELEMENT-WISE

All 256 entries of `crc32_tab` (poly 0xEDB88320, `icrc32.c:58-102`) and of
`crc32Table` (poly 0x82F63B78 = reflected 0x1EDC6F41, `icrc32.c:144-209`) match
tables generated bitwise in the harness. `sctp_crc_tableil8_o32` ==
`crc32Table`, and the seven higher sliced tables (`o40..o88`,
`icrc32.c:306-676`) each match the canonical iterative slicing construction
`T_{k+1}[i] = (T_k[i] >> 8) ^ T_0[T_k[i] & 0xff]`. There is **no runtime
table initialization at all** (compile-time `const` in `.rodata`), so the
"init once protocol" race class is structurally impossible. Check: `T1..T4`
PASS.

### (b) Update/final arithmetic — DIFFERENTIAL-TESTED

For **every length 0..600 × every buffer alignment 0..3** (random data, fixed
seed): `iscsi_crc32` == bitwise reference (init/xorout `~0`), `calculate_crc32c`
== bitwise raw, `singletable_crc32c` == bitwise raw (single-table engine tested
at all lengths, not just the `length < 4` gate at `icrc32.c:765`), and
`crc32`/`crc32_ext` (from `sys/libkern/crc32.c`, which links against
`crc32_tab` from this file) == bitwise reference. Known-answer vectors:
`"123456789"` → `0xCBF43926` (CRC-32) / `0xE3069283` (CRC-32C); empty → 0.
A 1 MiB random buffer exercises the full sliced-by-8 loop. Checks `T5,T6,T8`
PASS — **no silent-corruption divergence exists between the single-table,
multi-table, and bitwise implementations.**

**Boundary/OOB analysis (killed):** `multitable_crc32c` (`icrc32.c:750`)
computes `init_bytes = 4 - (buf & 3)` ∈ {1,2,3,4}; it is only reachable with
`length ≥ 4` (`icrc32.c:765-769`), so `length - init_bytes` never underflows
and `init + running + end == length` exactly. After the init loop the pointer
is 4-byte aligned, so the `*(const uint32_t *)p_buf` loads (`icrc32.c:707,723,726`)
are aligned (and benign anyway on x86). A PROT_NONE guard-page probe with data
ending exactly at an unmapped page for 256 boundary lengths (covering every
`L mod 8` × effective alignment) across `iscsi_crc32`, `calculate_crc32c`, and
`crc32` produced **zero faults** (T9 PASS). The big-endian byte-reconstruction
branch (`icrc32.c:701-705, 717-721`) was verified to be the LE-word equivalent
(moot: DragonFly is x86-only).

### (c) Consumers (who feeds lengths) — ALL BOUNDED

- `sys/kern/kern_dmsg.c:2009-2012` — `aux_crc`/`hdr_crc`; receive side clamps
  `aux_size > DMSG_AUX_MAX` → `EINVAL` (`kern_dmsg.c:371-376`); `hdr_size` is
  protocol-bounded.
- `sys/vm/swap_pager.c:1876` — `bp->b_bcount` ≤ MAXPHYS.
- `sys/vfs/hammer2/*` — `chain->bytes` is radix-derived, ≤ 64 KB
  (`hammer2_chain.c:5391,5416,5538,5584,5597`); volume-header CRCs are over
  fixed constants (`hammer2_ondisk.c:530-550`); filename CRCs bounded by
  PSTR_LEN (`hammer2_subr.c:197-216`).
- `sys/vfs/hammer/hammer_crc.h:73-77` — buffer sizes ≤ buffer I/O limits.
- `sys/vfs/ext2fs/ext2_csum.c` — block/group-descriptor-sized, seeded
  incremental raw chaining consistent with the non-inverting contract.
- `sys/kern/vfs_cache.c:3881-3883`, `sys/vm/vm_page.c:1581`,
  `sys/kern/vfs_mount.c:457` — `sizeof`/hash inputs.

None can reach `2^32` bytes, so the truncation below cannot be triggered
in-tree today.

### (d) State reuse — NONE POSSIBLE

All functions are pure: no mutable globals, no context struct, no lazy-init
flags; the only writable is the local `crc`. Reentrant/SMP-safe by
construction. Inversion protocol verified: `iscsi_crc32_ext(b,l,0)` ==
`iscsi_crc32(b,l)`, chained `ext(ext(0,a),b)` == one-shot over `a||b`, and
same for `crc32_ext` and raw `calculate_crc32c` chaining, including by-1 and
by-3 chunk churn across the `length<4` engine boundary (T7 PASS — after I
fixed a double-processing bug in my own harness's by-3 loop, not in the
kernel code).

## The defect that was filed (DF-5679, Info)

`iscsi_crc32`/`iscsi_crc32_ext` accept `size_t size`
(`sys/sys/systm.h:205-206`) but the length narrows to `unsigned int` at
`calculate_crc32c` (`icrc32.c:763`) and again inside
`crc32c_sb8_64_bit`/`multitable_crc32c` (`icrc32.c:686,743`). A request for
`0x100000009` bytes is silently serviced as 9 — an **integrity contract
violation** (data past the first 4 GiB would be unchecked), not an overflow:
the code *under-reads*. Contrast `crc32()`/`crc32_ext()` in
`sys/libkern/crc32.c:114-142` which honor `size_t` end-to-end.

**Runtime proof (reproduced, deterministic, guest):**
`iscsi_crc32(buf, 0x100000009ULL) == iscsi_crc32(buf, 9) == 4520c30c`
(T10; `fixdemo_baseline` prints the silent return). Impact: none reachable
today (bounds audit above) → Info, certain (the truncation is type-system
provable and machine-demonstrated).

**Fix validation:** `fix.diff` propagates `size_t` through
`calculate_crc32c`/`multitable_crc32c`/`crc32c_sb8_64_bit` and the two
prototype sites (`icrc32.c:15-16` userland, `sys/sys/systm.h:207`). Applied
to a copy and rebuilt: baseline `fixdemo` exits 1 with the silent truncation
(`fix_run.log`), patched `fixdemo` child faults on the guard page
(SIGSEGV) because the full `0x100000009` length is now honored
(`FIX-OK`, exit 0). Bad behavior gone → **fix_status: fixed**. A kernel
rebuild validation was not performed (userland rig; no memory-corruption
finding, so the mandatory kernel-rebuild rule does not apply).

## Honest accounting

Three rig iterations were needed (attempts=3): (1) first build exposed a
missing hunk in my `fix.diff` (userland prototype at `icrc32.c:15-16`) and a
`-Wparentheses` precedence bug in one harness CHECK; (2) first run's single
T7 failure was traced to my harness double-processing the last 3-byte chunk
(kernel exonerated); (3) clean ALL-PASS. Guest left up, `/tmp`-only
artifacts, no panic, `guest_dirty=0`.

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