# DF-4802 — `initsd()` verify loop retries a mismatched block forever: unbounded uninterruptible kernel loop (CWE-835); the mismatch was not reachable on this guest

* File: `sys/dev/raid/vinum/vinumrevive.c:526-565` (`initsd` verify
  path)
* Severity: Low (speculative; needs a device that returns data other
  than what was just written while the subdisk is `sd_initializing`)
* Bucket: base:raid
* Status: **not reproduced** on the md-backed guest (see analysis)

## The defect

```c
verified = 0;
while (!verified) {					/* vinumrevive.c:526 */
    ... write zeroes; biowait;				/* :527-536  */
    if (error) ...
    if ((error == 0) && verify) {			/* :539 */
        ... read back; biowait;			/* :540-548 */
        else if ((*bp->b_data != 0)
        ||(bcmp(bp->b_data, &bp->b_data[1], bp->b_bcount - 1))) {
            kprintf("vinum: init error ...");
            verified = 0;				/* :560  <-- retry forever */
        } else
            verified = 1;
    } else
        verified = 1;
}
```

There is **no retry bound**: a persistent readback mismatch (flaky
media, a lying device, or any concurrent writer that lands between the
zero-write and the readback) spins this loop in the ioctl thread
forever. The `biowait`s have no PCATCH, so the thread is unkillable
while it loops. (`initsd` is reached per-block from
`start_object`/`VINUM_SETSTATE(object_up, verify=1)`,
`vinumstate.c:883-887`.)

## Why it did not reproduce here (negative result with evidence)

The concurrent-writer angle was tested thoroughly on the guest
(`initlivelock.c`): a tight `pwrite` loop on the raw subdisk device
(`/dev/vinum/sd/vol.p0.s0`, `vinumstrategy` `VINUM_SD_TYPE` → `sdio`
directly, `vinumrequest.c:135-139`) hammering the exact block being
initialized — **zero mismatches in 3 full 3 MB inits**; the readback
never saw the concurrent garbage. Reason: `sdio()` dispatches via
`vn_strategy(drive->vp, ...)` (`vinumrequest.c:981`) — the init's
write+readback pair is served coherently from the vnode/buffer-cache
view, while the raw physio writer bypasses it; the verify effectively
re-reads its own just-written zeros. A raw concurrent writer therefore
cannot desync the pair on this backing, and the mismatch arm stayed
unreachable (no `vinum: init error` line was ever produced).

On real hardware with media that returns corrupted data (the case the
verify exists for), the loop is provably unbounded: there is no counter
and no error exit on the mismatch branch.

## Files

* `initlivelock.c` — the attempted trigger (init ioctls with verify=1 +
  concurrent raw-sd garbage writer; documents the buffer-cache
  shielding)
* `verdict.json`, `README.md`, `env.txt`
