# DF-5580 — UB shift counts in `__udivmodti4` masked-select initialization

**File:** `sys/platform/pc64/x86_64/__udivti3.c` (pass 2)
**Class:** reliance on undefined behavior (shift exponent ≥ width of the
shifted 64-bit operand, and shift counts computed from negative unsigned
wraparound) — CWE-1357. Severity: **Low** (hardening; no wrong results on
the shipping gcc 8.3 toolchain — proven by ~6.5 billion differential
vectors — but formally UB that a compiler upgrade can legally turn into
silent miscompilation of every in-kernel 128-bit division).

## What this pack contains

| Artifact | Meaning |
|---|---|
| `df5580_diff.c` | differential harness: `#include`s the kernel `__udivti3.c` verbatim and checks `__udivti3` + `__udivmodti4` (q and r) against native `unsigned __int128` division |
| `__udivti3.c` | verbatim copy of the audited kernel source (what the harness includes) |
| `ubsan_stub.c` | hand-written `__ubsan_handle_shift_out_of_bounds[_abort]` stubs (DragonFly gcc 8.3 ships no libubsan) so `-fsanitize=shift` instrumentation links |
| `run.log` | baseline differential, seeds `243f…:1319…`: **2,151,999,419 vectors, 0 mismatches** (345 s) |
| `run.2.log` | baseline differential, second seed set: **2,151,999,419 vectors, 0 mismatches** (343 s) |
| `ub_abort.log` | baseline under `-fsanitize=shift -fno-sanitize-recover=shift`: **aborts (rc 134) at `__udivti3.c:274:25`, shift=64 on a 64-bit operand** — the UB is live in the source |
| `ub_census.txt` | recover-mode census: **1,017,186 shift-UB events across all 10 masked-select shift sites** (`:231 :233 :235 :236 :238 :240 :242 :243 :274 :277`), including counts like `shift=4294967291` (0xFFFFFFFB = negative-wrapped `sr - 64`) |
| `kmod/` | KLD harness: `df5580_mod.c` drives the **running kernel's own exported `__udivti3`** (symbol at `0xffffffff80bdabb0`); `df5580_mod_fix.c` + `df5580_udivti3_fixed.c` compile the **patched** source with kernel CFLAGS |
| `kmod_kldtest_run.log` | in-kernel run: **268.7M vectors through the kernel symbol AND the patched source — both 0 mismatches vs native division** |
| `__udivti3_fixed.c`, `df5580_diff_fixed.c`, `run_fixed.log`, `ub_abort_fixed.log` | fix validation: patched source = same 2.15B-vector battery, 0 mismatches, **UBSan clean (rc 0)** |
| `mod_build.log`, `modfix_build.log` | module builds (note kernel flags: `-O2 -Werror -fno-strict-aliasing -fno-strict-overflow`) |
| `env.txt` | guest uname, compiler, kernel .comment, kldstat |
| `fix.diff` | the verified fix (un-comment the branchy init the file already documents; removes every out-of-range shift) |

## Reproduce

```
# on the DragonFly guest (gcc 8.3, same compiler that built the kernel):
cc -O2 -Wall -o df5580_diff df5580_diff.c
time ./df5580_diff x 2147483648 0x243F6A8885A308D3 0x13198A2E03707344   # ~6 min
# expect: TOTAL checked=2151999419 mismatches=0 / PASS

# prove the live UB:
cc -O1 -g -fsanitize=shift -fno-sanitize-recover=shift -c df5580_diff.c
cc -c ubsan_stub.c
cc -o df5580_ubsan df5580_diff.o ubsan_stub.o
./df5580_ubsan -e        # expect: UBSAN-FIRED ... __udivti3.c:274:25 ... shift=64, abort (rc 134)

# in-kernel (root):
cd kmod/df5580  && make SYSDIR=/usr/src/sys && kldload ./df5580.ko
cd ../df5580fix && make SYSDIR=/usr/src/sys && kldload ./df5580fix.ko
cc -O2 -o df5580_kldtest ../df5580_kldtest.c && ./df5580_kldtest 268435456
# expect: PASS: kernel baseline AND patched source match native division
```

`final_battery.sh` reruns the whole matrix and writes `status_*.txt` files
(remote login shell is csh; `$?` through ssh is unreliable).

## Why this matters even though results are correct today

The masked selects evaluate e.g. `(n.s.low << (n_utword_bits - sr))` with
shift counts up to 126 on a 64-bit operand whenever `sr <= 64`, and
`(n.s.low >> (sr - n_udword_bits))` with counts like 0xFFFFFFFB whenever
`sr < 64`. The result is then ANDed with a mask that is provably zero in
exactly those cases — semantically correct by construction, **formally UB**
at every evaluation. gcc/clang today lower this to `shl/shr %cl` and mask,
so the kernel's 128-bit divisions are correct; but the optimizer is
entitled under C11 6.5.7p3 to treat those evaluations as poison, and any
future compiler upgrade that hoists, combines, or simplifies around them
can silently corrupt every `muldivu64()` timer computation
(`sys/sys/systm.h:505`) — lapic/i8254 reload math, kern_clock timekeeping,
hyperv vmbus timing. Upstream compiler-rt long ago deleted this
branchless-mask version of `udivmodti4` for exactly this reason.

## Caller-contract notes (verified, not filed)

* `b == 0` divides by zero → x86-64 #DE → kernel panic
  (`__udivti3.c:116-117` and `:135-136`). Same contract as libgcc; every
  in-tree caller (`muldivu64`) passes timer frequencies/constants ≠ 0. The
  DF-5554 crafted-capacity class lives in 64-bit hardware `div` paths, not
  here.
* Only `__udivti3` is provided (no `__umodti3`); in-kernel 128-bit modulo
  with a runtime divisor cannot link — none exists in-tree.
