# DF-0239 — Missing `resume_kproc` implementation: suspend permanently freezes daemons

**Verdict: REPRODUCED (source-level).**
**Impact: DoS / availability** — a suspended kernel daemon (syncer, bufdaemon, swapcache,
mountd, printf, hptmv) never resumes; **not** memory corruption, no escalation chain.

## The bug

`resume_kproc()` is **declared** in `sys/sys/kthread.h:56` but **never defined** anywhere in
the tree:

```
$ grep -rn 'resume_kproc' sys/
sys/sys/thread.h:435:#define TDF_MP_WAKEREQ    0x00000002   /* resume_kproc */
sys/sys/kthread.h:56:int    resume_kproc (struct thread *);     <-- declaration, NO body
```

`sys/kern/kern_kthread.c` defines `suspend_kproc()` (187-206) and `kproc_suspend_loop()`
(208-224) but has **no** `resume_kproc()`. The suspend loop waits on a flag nothing ever sets:

```c
208: void
209: kproc_suspend_loop(void)
210: {
211:     struct thread *td = curthread;
212:     if (td->td_mpflags & TDF_MP_STOPREQ) {
213:         lwkt_gettoken(&kpsus_token);
214:         atomic_clear_int(&td->td_mpflags, TDF_MP_STOPREQ);
216:         while ((td->td_mpflags & TDF_MP_WAKEREQ) == 0) {   /* <-- nothing sets WAKEREQ */
217:             wakeup(td);
218:             tsleep(td, 0, "kpsusp", 0);                    /* sleeps FOREVER */
219:         }
220:         atomic_clear_int(&td->td_mpflags, TDF_MP_WAKEREQ);
...
```

Because `resume_kproc()` does not exist, `TDF_MP_WAKEREQ` is never set, so once a daemon calls
`kproc_suspend_loop()` after a `suspend_kproc()` request, it loops in `tsleep()` forever.

## Who is affected

`suspend_kproc()` callers (suspend requestors) and `kproc_suspend_loop()` sites (daemons):

- suspend: `kern_shutdown.c:939` (shutdown — permanent freeze is harmless there), `usb_process.c:61`
  (`USB_THREAD_SUSPEND`), `uvc_drv.c:1175`.
- suspend-loop (the frozen daemons): `vfs_sync.c:379` (syncer), `vfs_bio.c:2251` (bufdaemon),
  `vm_swapcache.c:234` (swapcache), `vfs_mount.c:529` (mountd), `subr_prf.c:931` (printf),
  `hptmv/entry.c:2467` (hptmv raid daemon).

So an ACPI suspend (or a USB suspend event, `sys/bus/u4b/usb_process.c`) that suspends these
daemons leaves them permanently frozen — they never resume. The USB subsystem itself even
warns about being "left suspended".

## Reachability

Suspend is a privileged/host-initiated event (ACPI S3, USB suspend). Not triggerable by an
unprivileged user on this guest, but the **missing implementation** is unambiguous: the
declared function has no body, so ANY code path that suspends a kproc is broken-by-design. The
bug is confirmed by source trace (the linker would also reject a kernel that *calls*
`resume_kproc` today — confirming no in-tree suspend/resume symmetry exists).

## The fix

`fix.diff` adds the missing `resume_kproc()` to `kern_kthread.c`, mirroring `suspend_kproc()`:
under `kpsus_token`, set `TDF_MP_WAKEREQ`, `wakeup(td)`, wait for the daemon to clear it, then
return. This unblocks `kproc_suspend_loop()` line 216 and restores suspend/resume symmetry.

## Kernel refs
- `sys/sys/kthread.h:56` — declaration of `resume_kproc` (no definition exists)
- `sys/kern/kern_kthread.c:216` — `while ((td->td_mpflags & TDF_MP_WAKEREQ) == 0)` infinite wait
- `sys/kern/kern_kthread.c:187` — `suspend_kproc` (the mirror that DOES exist)
- `sys/sys/thread.h:435` — `TDF_MP_WAKEREQ` flag nothing sets
