# DF-0595 — VERDICT

## Verdict

**REPRODUCED** (source-confirmed + primitive demonstrated) and **FIX VALIDATED**
(single-fix kernel built, installed, rebooted; vulnerable `memcmp` call
removed from both MIC-verification modules, replaced by `timingsafe_bcmp`).

## The finding (what was claimed)

`sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c:361` and
`sys/netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c:642` verify the
Michael MIC tag with libc `memcmp`. `memcmp` short-circuits on the first
differing byte, exposing a per-frame timing side-channel — the canonical
enabling primitive for Beck-Tews "chopchop"-style byte-by-byte MIC-forcing
attacks against TKIP. Severity: **Info** (defense-in-depth; in practice the
signal is sub-µs and dominated by WiFi RTT / softirq jitter, and is further
throttled by 802.11 MIC countermeasures — at most 2 MIC failures per 60 s
before the link shuts down).

## Confirmation (source-level)

Both cited lines are exactly as claimed, unmodified on the unpatched
`6.5-DEVELOPMENT #0` baseline:

```
sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c:361:
		if (memcmp(mic, mic0, tkip.ic_miclen)) {
sys/netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c:642:
	if (memcmp(mic, a, ccmp.ic_trailer) != 0) {
```

Both compare a fixed 8-byte tag (`IEEE80211_WEP_MICLEN = 8`).
`memcmp(3)` is documented to short-circuit; the branch/memory-access pattern
is therefore attacker-observable in principle.

## Primitive demonstration (runnable)

`mic_timing_demo.c` is a userspace timing-channel demonstration. It times
libc `memcmp` and the libkern `timingsafe_bcmp` XOR-accumulate idiom over
two adversarial cases of equal-length buffers:

- **first-byte-diff** — early `memcmp` exit after 1 compare
- **last-byte-diff** — full `memcmp` scan

Three runs on the unpatched `#0` guest:

| Run | memcmp ratio (256B) | ct_bcmp ratio (256B) | memcmp ratio (8B) | ct_bcmp ratio (8B) |
|-----|--------------------:|---------------------:|------------------:|-------------------:|
| 1   | 2.248               | 0.970                | 1.002             | 0.746              |
| 2   | 2.001               | 0.969                | 0.999             | 1.331              |
| 3   | 2.258               | 1.062                | 0.672             | 1.668              |

**Test 1 (256-byte, principle):** `memcmp`'s last/first ratio is a clean,
consistent **2.0–2.3×** across all runs; `timingsafe_bcmp`'s is flat
(**0.97–1.06**). This unambiguously proves the guest libc's `memcmp` is
short-circuit / non-constant-time — i.e. the primitive the finding warns
about genuinely exists in this environment.

**Test 2 (8-byte, the actual MIC length):** noisy — sometimes >1, sometimes
<1. This is exactly the finding's own thesis: at the real MIC length the
signal is real but tiny and swamped by jitter, dominated by WiFi RTT and
the `hostap_input` softirq path in deployment. This empirically confirms
the **Info** severity rating (not Critical).

The demonstration is kernel-independent (it targets libc) by design: the
guest has no WiFi hardware, so the in-kernel SWDEMIC path is not reachable
at runtime. Source-level confirmation plus primitive demonstration is the
correct bar for a timing side-channel of this class.

## No escalation (correctly)

This is a timing side-channel / hardening finding, not a memory-corruption
primitive. There is no escalation chain to develop — the impact ceiling is
"byte-by-byte MIC recovery via many precisely-timed frame injections,
heavily throttled by MIC countermeasures in practice", which is the
defense-in-depth concern the finding documents.

## Fix

`fix.diff` is a minimal, idiomatic one-token rename in each file: replace
`memcmp` with DragonFlyBSD's existing libkern `timingsafe_bcmp`. Rationale:

- `timingsafe_bcmp` is already in the tree (`sys/libkern/timingsafe_bcmp.c`,
  declared in `sys/sys/libkern.h:99`) and is already the idiom used by the
  crypto subsystem (`sys/crypto/chachapoly.c:195`,
  `sys/crypto/curve25519/curve25519.c`) and WireGuard
  (`sys/net/wg/wg_noise.c`, `sys/net/wg/wg_cookie.c`).
- It is already declared in both files' include chain: both include
  `<sys/socket.h>`, which includes `<sys/libkern.h>` "for bcmp()" at
  `sys/sys/socket.h:241`.
- Semantics match perfectly: `timingsafe_bcmp` returns non-zero on
  difference (like `bcmp`), so `if (memcmp(...))` and
  `if (memcmp(...) != 0)` are exactly equivalent to
  `if (timingsafe_bcmp(...))` / `if (timingsafe_bcmp(...) != 0)`.
- `tkip.ic_miclen` / `ccmp.ic_trailer` are compile-time-constant 8, so the
  XOR-accumulate loop is fully unrollable.

This **supersedes** the finding markdown's proposed inline-XOR-loop fix,
which is functionally equivalent but reinvents `timingsafe_bcmp` and
introduces awkward brace nesting. Using the existing libkern helper is the
DragonFlyBSD-idiomatic form.

## Fix validation (Phase 8)

1. **Baseline (`#0`, unpatched):** confirmed `memcmp` at the cited lines in
   `/usr/src`; primitive demonstrated (Test 1 ratios 2.0–2.3×).
2. **Applied `fix.diff`** to in-guest `/usr/src` via `patch -p1` — both
   hunks applied cleanly (`PATCH_EXIT=0`).
3. **Built single-fix kernel:** `make -j6 nativekernel KERNCONF=X86_64_GENERIC`
   → `NK_DONE rc=0`. (Full build log in `fix_build.log`.)
4. **Object-level proof of the fix** (before reboot):
   - `ieee80211_crypto_tkip.o`: `U timingsafe_bcmp` (was `memcmp`)
   - `ieee80211_crypto_ccmp.o`: `U timingsafe_bcmp` (was `memcmp`)
   - `objdump -dr wlan_tkip.ko` shows `tkip_demic+0xd5: callq ... R_X86_64_PLT32 timingsafe_bcmp-0x4`
5. **Installed + rebooted** (`make installkernel`; overwrote bare
   `/boot/kernel/kernel` with the stripped build after clearing `schg`;
   rebooted). Patched kernel `kern.version`:
   `DragonFly 6.5-DEVELOPMENT #1: Tue Jul 14 21:30:33 UTC 2026`
   (sha256 `56317050...17194f27`).
6. **Running-kernel module audit (after):**
   - `/boot/kernel/wlan_tkip.ko` + `/boot/kernel/wlan_ccmp.ko`:
     `U timingsafe_bcmp` ×2, **`U memcmp` ×0**.

**Before/after contrast** (the negation of the bad-behavior marker
"`memcmp` present in MIC verification"):

- **Before (`#0`):** `memcmp(mic, mic0, ...)` at tkip.c:361,
  `memcmp(mic, a, ...) != 0` at ccmp.c:642; modules reference `memcmp`.
- **After (`#1`):** both call sites use `timingsafe_bcmp`; installed
  modules reference `timingsafe_bcmp` (×2) and `memcmp` (×0).

`fix_status = fixed`.

## PoC changes

- Added `mic_timing_demo.c` (runnable primitive demonstration) — the
  finding shipped with no PoC ("defense-in-depth, not exploited"). The demo
  makes the finding's premise concrete and runnable on the static site
  without requiring WiFi hardware.
- Added `fix.diff` (authored post-verification; supersedes the finding
  markdown's inline-loop proposal with the idiomatic `timingsafe_bcmp`).
- Added `build.sh`, `run.sh`, `VERDICT.md`, `manifest.json`, full logs,
  `env.txt`.
