uvisor_attach/uvisor_init: up to 2Γ synchronous 5000 ms-timeout EP0 control requests on the per-bus USB explore thread before the port exists; an evil Visor/Palm/Clie VID:PID adapter pins bus-wide device enumeration for ~5 s (10 s for SONY CLIE_35) per insertion
Summary
uvisor_init runs on the per-bus explore thread and chains sync requests at the 5000ms default (VISOR 1x, PALM4 1x, PALM35 2x) before ucom_attach: an evil adapter NAK-ing just-under-timeout pins ALL insertion/removal/enumeration events for the bus ~5-10s per insertion, repeatable by re-plug. Verbatim-production-extraction harness: VISOR 4796/4802ms, PALM4 4794/4803ms, PALM35 9591/9609ms with the exact production EP0 trace; 250ms-bound + abort fix mechanism ~250ms. Same class as DF-5407/5359.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5488 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.4 KB | β raw | |
| VERDICT.md | β | 4.8 KB | β raw | |
| uvisor_stall_harness.c | β | 7.2 KB | view raw | |
| Makefile | β | 127 B | β download | |
| build.sh | β | 236 B | view raw | |
| run.sh | β | 136 B | view raw | |
| build.log | β | 7.1 KB | view raw | |
| run.log | β | 2.5 KB | view raw | |
| run.2.log | β | 611 B | view raw | |
| fix.diff | β | 1.8 KB | view raw | |
| fix_compile.log | β | 7.2 KB | view raw | |
| env.txt | β | 443 B | view raw | |
| verdict.json | β | 5.1 KB | view raw |
DF-5488 β uvisor_attachβuvisor_init: up to 2Γ synchronous 5000 ms-timeout
EP0 requests on the per-bus USB explore thread; an evil Visor/Palm/Clie
VID:PID adapter pins bus enumeration for ~5-10 s per insertion
The chain (production code, executed verbatim in the harness)
uvisor_attach() (uvisor.c:302-354) runs on the per-bus USB explore
thread and calls uvisor_init() (uvisor.c:326 β 370-517) BEFORE any ucom
port exists, issuing synchronous control requests at the
USB_DEFAULT_TIMEOUT of 5000 ms (usbdi.h:87):
| sc_flag (VID:PID table, uvisor.c:248-278) | requests | uvisor.c | worst |
|---|---|---|---|
UVISOR_FLAG_VISOR (HANDSPRING VISOR 082d:0100) |
1Γ GET_CONNECTION_INFORMATION vendor IN (wLength 18) | 382-389 | ~5 s |
UVISOR_FLAG_PALM4 (Treo, Palm m*/i705/Tungsten/Zire, Clie S360/NX60/TJ37, Garmin, Fossil, AlphaSmart, Tapwave, Samsung) |
1Γ GET_PALM_INFORMATION vendor IN (wLength 0x44) | 434-442 | ~5 s |
UVISOR_FLAG_PALM35 (SONY CLIE_35) |
2Γ standard requests (UR_GET_CONFIG + UR_GET_INTERFACE) | 476-485, 488-496 | ~10 s |
USB permits a device to NAK a control data stage for the entire 5 s timeout; an evil adapter (Facedancer/gadget with one of these VID:PIDs) answering each request just-under-timeout β or never answering β pins the explore thread (which serializes ALL device enumeration on that bus: exploration, insertion and removal events) for the full chain, while each request additionally holds the per-device enum lock (usb_request.c:467). On timeout the attach fails cleanly (uvisor.c:391-393 etc.), but the stall has already happened. Same class as DF-5407 (uplcom, 14Γ5 s β 70 s, Medium) and DF-5359 (uipaq, ~12.8 s, Low); uvisor's worst case is 2Γ5 s (CLIE_35), typical 5 s.
Evidence class
No Visor/Palm QEMU device model exists β verbatim-production-extraction
KLD harness (the DF-5407 evidence class): build.sh sed/awk-extracts
the production uvisor_init() VERBATIM from the guest's clean
/usr/src/sys/bus/u4b/serial/uvisor.c (defines/structs = lines 85-182 β
uv_defs.h; function = anchor-extracted β uv_init.h; extraction sha256s
recorded in build.log and re-verified reproducible) and only the EP0
entry point it calls (usbd_do_request_flags, which usbd_do_request
macro-expands to, usbdi.h:511-512) is re-targeted to an evil-device model
(NAK ~4.9 s then answer, USB-legal). Phase B re-extracts from a scratch
copy patched with fix.diff (pure uvisor_initβuvisor_init_fixed rename).
Reproduce
./build.sh # verbatim extraction + in-tree kmod build, -Werror clean ./run.sh # kldload; dmesg | grep HX5488
Expected (phase A, evil in-spec-slow answers): VISOR ~4.8 s, PALM4 ~4.8 s,
PALM35 ~9.6 s, all err=USB_ERR_NORMAL_COMPLETION.
Expected (phase B, 250 ms driver-side bound): all three ~0.25 s,
err=USB_ERR_TIMEOUT (chain aborts).
Observed (two runs): VISOR 4796/4802 ms, PALM4 4794/4803 ms,
PALM35 9591/9609 ms; fixed: 250/265, 259/261, 249/272 ms (run.log,
run.2.log). The request trace (bmRequestType 0xc2/0x80, bRequest
0x03/0x04/0x08/0x0a, wLength 18/68/1/1) matches production exactly; the
PALM4 run also shows device-supplied data flowing through the extracted
code into config[].endpoint (10/5 from the 0x5A-filled answer).
Fix
fix.diff bounds the attach-path control timeout to 250 ms
(UVISOR_INIT_TIMEOUT, same bound as the uplcom DF-5407 family fix) for
all four call sites. The patched production uvisor.ko compiles -Werror
clean (fix_compile.log).
DF-5488 VERDICT β REPRODUCED (verbatim production code)
Finding: uvisor_attach() β uvisor_init() (uvisor.c:326, 370-517)
issues up to two synchronous EP0 control requests at the 5000 ms
USB_DEFAULT_TIMEOUT (usbdi.h:87) on the per-bus USB explore thread,
before the ucom port exists: 1Γ vendor IN for VISOR devices
(uvisor.c:382-389), 1Γ vendor IN for PALM4 devices (uvisor.c:434-442),
2Γ standard requests for PALM35 devices (uvisor.c:476-496). An evil
adapter with one of the 28 VID:PIDs in uvisor_devs[] (uvisor.c:248-278)
that NAKs the data stages pins bus-wide enumeration for the full chain
(~5 s typical, ~10 s for CLIE_35), holding the per-device enum lock
(usb_request.c:467) per request. Same class as DF-5407 (uplcom ~70 s,
Medium) / DF-5359 (uipaq ~12.8 s, Low).
Reproduction (verbatim-production-extraction harness, DF-5407 class)
The production uvisor_init() is extracted VERBATIM from the guest's
clean tree and compiled into the harness KLD; only the EP0 entry point
it calls is re-targeted to an evil-device model (NAK ~4.9 s β answer,
USB-legal; this is the worst case because the chain then continues to
the next request). Guest and audited host tree are identical
(uvisor.c sha256 b742032f0dab0dc9c5cbfd63432834c00828390ddfe97f3410298f
d703844438). Extraction itself is reproducible (sha256s re-recorded
post-run and matching build.log: uv_defs.h 7911b455β¦, uv_init.h
63a03e13β¦).
Measured (hz=100 guest, two runs each):
| variant | phase A (evil) | phase B (250 ms bound) |
|---|---|---|
| VISOR (sc_flag=0x0002) | 4796 / 4802 ms | 250 / 265 ms |
| PALM4 (sc_flag=0x0001) | 4794 / 4803 ms | 259 / 261 ms |
| PALM35 (sc_flag=0x0004) | 9591 / 9609 ms | 249 / 272 ms |
Decisive lines (run.log / run.2.log):
HX5488: PALM35 (Sony Clie 3.5): uvisor_init() DONE err=USB_ERR_NORMAL_COMPLETION ELAPSED=9591 ms
HX5488: VISOR β¦ ELAPSED=4796 ms, HX5488: PALM4 β¦ ELAPSED=4794 ms
Full EP0 trace confirms the exact production requests:
bmRequestType=0xc2 bRequest=0x03 wLength=18 (GET_CONNECTION_INFORMATION),
bmRequestType=0xc2 bRequest=0x04 wLength=68 (GET_PALM_INFORMATION),
bmRequestType=0x80 bRequest=0x08 wLength=1 (UR_GET_CONFIG) +
bRequest=0x0a (UR_GET_INTERFACE). The PALM4 run additionally shows the
device-supplied endpoint bytes flowing through the verbatim code into
config[].endpoint (cfg endpoints 10/5 from the 0x5A-filled response).
Why this is the production behavior
uvisor_attach()callsuvisor_init(sc, uaa->device, uvisor_config_copy)at uvisor.c:326 before ucom_attach; attach runs on the per-bus explore thread (established family-proven in DF-5407/DF-5359: usb_needs_explore β usb_bus_explore β device attach serializes the bus).- Each request is
usbd_do_request_flags(..., USB_DEFAULT_TIMEOUT)/usbd_do_request(...)(macro β same, usbdi.h:511-512), whose "WXFER" wait loop sleeps until completion or timeout (usb_request.c:642-644, 699-704). A NAK-ing device burns the full 5000 ms per request. - On timeout,
erraborts the chain (uvisor.c:391-393, 444-446, 483-485, 494-496) and attach fails β but the multi-second explore-thread stall has already happened; a gadget device can also answer at 4.9 s to keep the chain going (modeled in phase A).
Severity
Low β bounded (~5-10 s per insertion), requires an evil/malfunctioning Visor-family adapter; family precedent (DF-5359 at ~12.8 s = Low, DF-5407 at ~70 s = Medium). Impact: bus enumeration latency / hub event thread stall, no corruption, no leak.
Fix validation
fix.diff adds UVISOR_INIT_TIMEOUT (250 ms) and uses it at all four
call sites (vendor coninfo, palm info, GET_CONFIG, GET_INTERFACE).
Validated two ways:
1. Harness phase B re-extracts the patched function verbatim (renamed):
all three variants collapse to ~250 ms with USB_ERR_TIMEOUT and a
clean chain abort.
2. The fully patched production uvisor.c compiled -Werror clean as a kmod
on the guest (fix_compile.log, RC=0).
Negative results / what was checked and killed
- PALM4 short-transfer uninit: the
actlen < 12check (uvisor.c:447-451) covers exactly the bytes later consumed (offsets 1, 8, 9 ofuvisor_palm_connection_info), so no uninitialized read on that path (the unguarded sibling is the VISOR path β DF-5489). - Device-supplied endpoint nibbles (uvisor.c:452-460) only feed
usbd_transfer_setupendpoint matching (uvisor.c:333-335), which validates type/direction against the real interface descriptors. - Guest left clean: harness dirs removed, production uvisor.c untouched.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
fixedfix.diff applied to a scratch copy of the guest's /usr/src uvisor.c: the patched function re-extracted verbatim (renamed) runs at 250/265, 259/261, 249/272 ms with USB_ERR_TIMEOUT aborts (vs 4.8-9.6 s baseline), and the fully patched production uvisor.ko compiled -Werror-clean RC=0 (fix_compile.log). The multi-second explore-thread occupancy is GONE under the fix.
fix.diff (git apply --check clean on host; patch -p5 clean on guest); run.log/run.2.log phase-B lines; fix_compile.log (RC=0); VERDICT.md 'Fix validation'.
Confirmed kernel references
Detail
Exploit chain
Evil USB adapter (Facedacer/gadget) presenting a VID:PID from uvisor_devs[] (uvisor.c:248-278: HANDSPRING VISOR/Treo, PALM m*/Tungsten/Zire, SONY CLIE_35, etc.) -> uvisor_attach() runs uvisor_init() on the per-bus USB explore thread -> the adapter NAKs each control data stage for just-under the 5 s timeout (or never answers) -> bus-wide device enumeration (explore/insert/remove events) is pinned ~5 s per request, up to ~10 s for a CLIE_35-VID:PID device, per insertion; repeatable by re-plugging.
Evidence (decisive lines)
run.log/run.2.log: 'HX5488: PALM35 (Sony Clie 3.5): uvisor_init() DONE err=USB_ERR_NORMAL_COMPLETION ELAPSED=9591/9609 ms', 'VISOR ... 4796/4802 ms', 'PALM4 ... 4794/4803 ms'; full per-request EP0 trace with bmRequestType/bRequest/wLength matching uvisor.c production call sites; phase-B fixed lines '~250 ms err=USB_ERR_TIMEOUT'; build.log: verbatim-extraction sha256s + -Werror kmod build; fix_compile.log: patched production uvisor.ko RC=0.
PoC changes
No seed PoC existed; authored from scratch on the DF-5407 verbatim-extraction pattern. Bring-up fixes: (1) USB_ERR_OK -> USB_ERR_NORMAL_COMPLETION (DF u4b enum name); (2) missing uv_init_fixed.h include; (3) usb_process.h/condvar.h/stdint.h include order; (4) a '/' sequence inside my own header comment (the text 'Treo/Palm m/Clie') terminated the C comment and broke the parse -- reworded; all documented in build.log history.
Verified recommended fix
Bound the attach-path control-request timeout to 250 ms (UVISOR_INIT_TIMEOUT) at all four uvisor_init() call sites (full diff in fix.diff).
Verdict
REPRODUCED with the production code VERBATIM (DF-5407 evidence class): uvisor_init() is sed/awk-extracted unchanged from the guest's clean tree (extraction sha256s recorded and re-verified; guest tree == audited tree, uvisor.c sha256 b742032f...) and only its EP0 entry point (usbd_do_request_flags, to which usbd_do_request macro-expands, usbdi.h:511-512) is re-targeted to an evil-device model that NAKs ~4.9 s then answers (USB-legal worst case: the chain continues). Phase A per-insertion explore-thread occupancy: VISOR 4796/4802 ms (1 x GET_CONNECTION_INFORMATION, uvisor.c:382-389), PALM4 4794/4803 ms (1 x GET_PALM_INFORMATION, uvisor.c:434-442), PALM35 9591/9609 ms (UR_GET_CONFIG + UR_GET_INTERFACE, uvisor.c:476-496) -- all at the 5000 ms USB_DEFAULT_TIMEOUT (usbdi.h:87) with each request serializing behind the per-device enum lock (usb_request.c:467). The EP0 trace (0xc2/0x03/len18, 0xc2/0x04/len68, 0x80/0x08, 0x80/0x0a) matches production exactly, and the PALM4 run shows device-supplied endpoint bytes flowing through the verbatim code into config[].endpoint. Fix mechanism (UVISOR_INIT_TIMEOUT 250 ms bound at all four call sites): all variants collapse to ~250 ms with USB_ERR_TIMEOUT and a clean chain abort; fully patched production uvisor.ko compiled -Werror-clean RC=0.
No comments yet.