# DF-5425 — uslcom cfg-chain EP0 stall (evil CP210x)

## What (human-readable)

`sys/bus/u4b/serial/uslcom.c` issues **sequential synchronous EP0 vendor control
requests** from its ucom cfg callbacks and **discards every result**:

* `uslcom_param()` (uslcom.c:505-583) — fired on **every tcsetattr** of an open
  tty — chains **3** requests: `USLCOM_BAUD_RATE` divisor write (uslcom.c:514-523,
  request issued at 520), `USLCOM_DATA` format write (uslcom.c:551-560, at 557),
  `USLCOM_SET_FLOWCTRL` 16-byte out (uslcom.c:573-582, at 579).
* `uslcom_open()` (uslcom.c:406-425) — every open(2) — adds **1** (`USLCOM_UART`
  enable, at 418).
* `uslcom_close()` (uslcom.c:427-446) — every close(2) — adds **1** (`USLCOM_UART`
  disable, at 442).
* Every request is `ucom_cfg_do_request(..., 1000)` with a **1000 ms timeout**,
  and every call site throws the `usb_error_t` away — "failed (ignored)" at
  uslcom.c:420, 522, 559, 581, 444 — so **no chain step ever aborts**.

An evil CP210x-clone (probe is VID/PID-table only, uslcom.c:208-293/328-345; 80+
VID:PID pairs) that simply never answers the control data/status stage makes each
request eat its full timeout (usb_request.c:642-644 "WXFER" sleep loop,
699-704 timeout) and the chain marches on: **~3.1 s per tcsetattr, ~1.1 s per
open, ~1.0 s per close**. A device that answers at just-under-timeout makes every
request *succeed* slowly — same cost, and no error to abort on.

uslcom amplifier: while the port is open, the watchdog (uslcom.c:315-326, rearmed
at hz/4 by uslcom_open:424) keeps an RCTRL control xfer in flight on the shared
ep0 endpoint queue (uslcom.c:756-770, 1 s timeout), so cfg requests can queue
behind up to ~1 s of in-flight status polling — the measured floors below do not
include this.

## Who blocks

* The chain runs on the per-adapter ucom taskqueue (`sc_super_ucom.sc_tq`,
  usb_serial.c:322) holding `sc->sc_lock`.
* **close(2) is synchronous against that queue**: `ucom_close()` →
  `ucom_queue_command(ucom_cfg_close)` → `usb_proc_mwait()` (usb_serial.c:671-672,
  955-957), an **uninterruptible** cv_wait (usb_process.c:385-393); a message
  stays head-of-queue for its whole callback (usb_process.c:146-158).
* **Unplug** stalls the USB hub event thread the same way via `ucom_detach()` →
  `usb_proc_drain()` (usb_serial.c:394) — the DF-5367 mechanism, uslcom instance.
* Any local user with the tty open (`/dev/cuaU*` is uucp:dialer 0660,
  usb_serial.c:483-488) **multiplies** the occupancy: each tcsetattr re-queues the
  param task into ucom's double buffer (usb_serial.c:1691-1693) — two outstanding
  tasks ≈ **~8.2 s** of uninterruptible close(2)/unplug block, repeatable
  indefinitely.

## Reproduce (no CP210x device model exists on the QEMU guest → KLD harness)

Same evidence class as DF-5367/DF-5383/DF-5421: the harness drives the real
in-kernel `usb_process` machinery (create/msignal/mwait/free — the exact
taskqueue plumbing of ucom's synchronous close and detach drain) with uslcom's
production chain shapes (1 req/open-task + hz/10, 3 reqs/param-task + hz/10,
1 req/close-task, 1000 ms/request).

```
# on the guest
sh build.sh          # in-tree kmod build, -Werror clean -> uslcomcfgstall.ko
sh run.sh            # kldload (phases run at MOD_LOAD), kldunload, dmesg
```

Expected decisive lines (two runs measured):

| Phase | Meaning | run 1 | run 2 |
|-------|---------|-------|-------|
| `[A]` | open + 1 tcsetattr + close (baseline) | **5078 ms** | **5090 ms** |
| `[2]` | open + 2 tcsetattrs + close (user-amplified) | **8141 ms** | **8094 ms** |
| `[B]` | fix #1: abort chain on first failed request | 3149 ms | 3121 ms |
| `[C]` | fix #1+#2: abort + 250 ms cfg timeout bound | 899 ms | 925 ms |

## Fix

`fix.diff` (git-apply-able against `sys/`, verified): (1) `uslcom_param()` aborts
on the first failed request (baud/format/flow are one unit); (2) all cfg-path
control timeouts bounded 1000 → 250 ms via `USLCOM_CFG_TIMEOUT` (open/close/
dtr/rts/break/param) — the ioctl path keeps 1000 ms since it only prices the
caller's own thread. The patched production driver compiles `-Werror`-clean as
the in-tree `uslcom.ko` (fix_compile.log).

## Impact

Availability-only: local unprivileged user (dialer group) + physical evil USB
device ⇒ uninterruptible multi-second close(2)/unplug stalls, repeatable;
per-family calibration = Low (DF-5367/DF-5383/DF-5421/DF-5424).
