# DF-5448 — uvscom_cfg_read_status() returns uninitialized kernel stack on a
# successful *short* vendor control-IN response

## The bug

`sys/bus/u4b/serial/uvscom.c:714-734`:

```c
static uint16_t
uvscom_cfg_read_status(struct uvscom_softc *sc)
{
	struct usb_device_request req;
	usb_error_t err;
	uint8_t data[2];                    /* <-- UNINITIALIZED stack */

	req.bmRequestType = UT_READ_VENDOR_DEVICE;   /* 0xC0: device-to-host */
	req.bRequest = UVSCOM_READ_STATUS;
	USETW(req.wValue, 0);
	USETW(req.wIndex, 0);
	USETW(req.wLength, 2);

	err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
	    &req, data, 0, 1000);
	if (err) {
		DPRINTFN(0, "device request failed, err=%s (ignored)\n", ...);
	}
	return (data[0] | (data[1] << 8));   /* <-- may be uninit */
}
```

Core semantics (`sys/bus/u4b/usb_request.c:783-788`,
`usbd_do_request_proc`):

```c
	/* on failure we zero the data */
	/* on short packet we zero the unused data */
	if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) {
		if (err)
			memset(data, 0, len);          /* error: fully zeroed */
		else if (actlen && *actlen != len)
			memset(((uint8_t *)data) + *actlen, 0, len - *actlen);
	}
```

The short-read tail zeroization only happens when `actlen != NULL` — but
`ucom_cfg_do_request` (`sys/bus/u4b/serial/usb_serial.h:220-221`) hardcodes
`actlen = NULL`:

```c
#define	ucom_cfg_do_request(udev,com,req,ptr,flags,timo) \
    usbd_do_request_proc(udev,&(com)->sc_super->sc_tq,req,ptr,flags,NULL,timo)
```

So:
- request **fails** (STALL/timeout): buffer zeroed → return 0. Safe.
- request **succeeds with a short data stage** — a control-IN transfer that
  ends in a 0-byte short packet leaves *both* bytes uninitialized; a 1-byte
  response leaves `data[1]` uninitialized (`usb_request.c:662-665` copies
  only `acttemp` bytes, `680-681`) → `return (data[0] | (data[1] << 8))`
  reads uninitialized kernel stack. Exactly the DF-1062/DF-2342 (uchcom)
  class, reached through the DF-5438 (ulpt)-style gap.

## Impact

**Currently none reaches userspace**: the sole caller
`uvscom_cfg_open()` (uvscom.c:640) *discards* the return value, and
`sc_lsr` / `sc_msr` / `sc_unit_status` are fed only from the interrupt pipe
(uvscom.c:425-446). The uninitialized value is computed and thrown away —
a latent hazard, not a live leak: it becomes a real kernel-stack disclosure
the moment any code consumes the return (the NetBSD original this driver
was ported from uses exactly such a status read to update the modem-status
state). Filed as hardening: initialize the buffer (defense in depth, same
treatment the core already gives the error path).

## Evidence

Static, code-certain (no SUNTAC device model exists for execution; the
Info-severity class was not executed — see verdict.json
status=untested). Path: uvscom.c:719,733 → usb_serial.h:220-221 →
usb_request.c:662-665, 680-681, 783-788.

## Fix

`fix.diff` — one line: initialize `data`. (Optionally the core macro could
pass a real `actlen`; that is a ucom-wide change tracked with the family.)

## Files
- `README.md`, `VERDICT.md`, `fix.diff`, `manifest.json`, `verdict.json`
- `fix_compile.log` — patched uvscom.ko compiles clean (combined guest build)
