Commit graph

195 commits

Author SHA1 Message Date
2e2a5961d6 fix: update nusb rev in both lib and cli, update flake cargoHash
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:17:10 +00:00
da9560cd99 fix: update nusb to rev with fixed fuzz_parse_concatenated_config_descriptors return type
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:13:33 +00:00
565e0f5834 feat: add nix fuzz devShell and fuzz-usbip app with --fork support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:08:55 +00:00
dfc7e366d9 feat: add fuzz_urb_cdc target
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:06:36 +00:00
963c96cf8b feat: add fuzz_urb_uac target
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:06:32 +00:00
4ccae7bf37 feat: add fuzz_urb_hid target
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:06:24 +00:00
0e6b602b1d feat: add fuzz_handle_client target
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:06:20 +00:00
60bef00b00 feat: add fuzz crate scaffold and fuzz_parse_command target
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:06:17 +00:00
c59bb719d5 feat: add fuzz_helpers module with response validation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 22:00:17 +00:00
72e9ba292e refactor: extract MockSocket to cfg(any(test, fuzz)) module
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:59:04 +00:00
d7f630500d feat: add fuzz feature flag and arbitrary dependency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:58:24 +00:00
c8c7c3271f docs: add implementation plan for fuzzing setup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:55:21 +00:00
1cb95dd57c docs: add spec for fuzzing setup targeting host codepaths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:49:39 +00:00
e0aa6bfbf6 refactor: remove rusb backend, keep only nusb
- Delete lib/examples/ (unused upstream leftovers)
- Remove rusb crate dependency
- Define local Direction enum in consts.rs (Out=0x00, In=0x80)
- Remove RusbUsbHostInterfaceHandler and RusbUsbHostDeviceHandler
- Replace rusb device enumeration with nusb in new_from_host*
- Update flake.nix cargoHash and Cargo.lock

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:19:51 +00:00
80083fdf93 docs: add spec for removing rusb backend and lib/examples
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:03:20 +00:00
9f270e271d docs: clarify Direction enum discriminant values in spec
Values are intentionally USB-spec-aligned (0x00/0x80), not rusb-aligned.
Safe since the enum is only pattern-matched, never cast to integer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:22:50 +00:00
c2742138f7 docs: fix spec gaps — add consts.rs Direction, device.rs Version, protocol comment
Spec reviewer caught three missing items that would cause build failures:
- pub use rusb::Direction needs local replacement enum
- rusb::Version conversion impls in device.rs need removal
- stale rusb::Direction comment in usbip_protocol.rs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:19:48 +00:00
8002dfa9e5 docs: add spec for removing rusb backend and lib/examples
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:17:12 +00:00
2a8247c909 Update README.md 2026-03-25 13:14:19 +00:00
ed4fa758f1 fix: guarantee RET_SUBMIT before RET_UNLINK wire ordering
The previous TOCTOU fix prevented sending both responses from two
threads, but a channel-ordering problem remained: the spawn_blocking
task and the UNLINK handler both sent to the same mpsc channel from
different threads, so RET_UNLINK could arrive at the kernel before
RET_SUBMIT.  The kernel (vhci_rx.c) then gives back the URB via the
unlink path, and the subsequent RET_SUBMIT triggers "cannot find a
urb" → VDEV_EVENT_ERROR_TCP → device disconnect.

Fix by making the spawn_blocking task the sole sender of RET_UNLINK
when the URB is still in-flight.  The UNLINK handler now stores its
response header in the InFlightUrb entry instead of sending
immediately.  The spawn_blocking task drains this after sending
RET_SUBMIT (or instead of it, if cancelled), guaranteeing same-thread
FIFO ordering through the channel.  The UNLINK handler only sends
RET_UNLINK directly for the "not found" case, where the entry has
already been removed — meaning RET_SUBMIT is already in the channel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:53:49 +00:00
80a9f35e39 fix: close TOCTOU race in UNLINK handling that crashes vhci_hcd
The spawn_blocking task checked is_cancelled() before removing the URB
from in_flight, allowing the UNLINK handler to find the entry, cancel
the token, and send RET_UNLINK(status=0) in the gap — while the task
proceeded to also send RET_SUBMIT. Both responses for the same URB is
a fatal protocol violation: if the kernel receives RET_UNLINK first it
gives back the URB, then RET_SUBMIT can't find it and disconnects.

Fix by removing from in_flight before checking is_cancelled(), making
the UNLINK handler and completion path mutually exclusive on the map.

Also downgrade "not found in-flight" to trace — it's a normal race for
isochronous transfers, not an error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:35:38 +00:00
c56dced930 fix: revert ISO packet descriptor byte order change
The ISO packet descriptors in this kernel's USB/IP implementation use
big-endian encoding (consistent with the rest of the protocol header),
not little-endian as assumed from older kernel source. The LE change
caused length=192 to be read as 0xC0000000, immediately failing the
bounds check on the first isochronous URB.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:09:53 +00:00
075ec146e4 fix: UAC1 audio device recognition, idle timeout, and ISO byte order
Three fixes for the UAC1 loopback test device:

- Add CS_ENDPOINT descriptors (type 0x25) after audio streaming isochronous
  endpoints. The Linux snd-usb-audio driver requires these to recognize the
  device. Added class_specific_descriptor field to UsbEndpoint (mirroring the
  existing field on UsbInterface) and emit it in the config descriptor builder.

- Remove the 30s URB read timeout from handle_urb_loop. The connection lifetime
  is managed by the kernel (vhci_hcd closes the socket on device detach). An
  application-level timeout killed healthy idle devices. Fixed tests to properly
  shutdown() write halves instead of relying on the timeout.

- Fix ISO packet descriptor byte order from big-endian to little-endian. The
  USB/IP protocol uses big-endian for header fields but little-endian for ISO
  descriptors (matching the kernel's usbip_pack_iso using cpu_to_le32). With
  big-endian, field values like length=192 were byte-swapped to ~3GB, corrupting
  isochronous audio streams.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:52:31 +00:00
18a413870a feat: add UAC1 loopback test device and fix endpoint attribute dispatch
Add a simulated USB Audio Class 1 loopback device for testing
isochronous transfers. Audio sent to the playback OUT endpoint
(48kHz/16-bit/stereo) is looped back to the capture IN endpoint.

- Add UsbEndpoint::transfer_type() masking bmAttributes to bits 0-1,
  fixing dispatch for isochronous endpoints with sync-type sub-bits
- Update all endpoint attribute dispatch sites across the library
- Add UacLoopbackBuffer, UacControlHandler, UacStreamOutHandler,
  UacStreamInHandler in lib/src/uac.rs
- Add build_uac_loopback_device() builder function
- Add `test_uac connect` CLI subcommand
- Add 10 unit tests covering buffer, descriptors, and handler behavior
- Add design spec and implementation plan docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:43:31 +00:00
e4cdc4beec Update .gitignore, remove obsolete plan doc 2026-03-25 00:30:38 +00:00
5120b1a3b9 fix: improve reliability with typed error handling and poison recovery
- Replace string-based USB error classification with ErrorKind matching:
  nusb TransferError is now preserved through io::Error instead of being
  destroyed by format!(). Stall→ConnectionReset→EPIPE, Cancelled→
  Interrupted→ENOENT, Disconnected→ConnectionAborted→ESHUTDOWN.
- Replace fragile string matching in interrupt IN retry loop with direct
  TransferError::Cancelled pattern match.
- Replace 21 production Mutex::lock().unwrap() calls with
  .unwrap_or_else(|e| e.into_inner()) to recover from mutex poisoning
  instead of cascading panics across the server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:21:10 +00:00
804a4910a0 fix: USB spec conformance and reliability improvements
Spec conformance:
- Add missing standard control requests for simulated devices:
  GetConfiguration, GetStatus (device/interface/endpoint),
  ClearFeature, SetFeature, SetAddress
- Replace debug_assert with truncate for path/bus_id wire format
  to prevent protocol desync in release builds

Reliability:
- server() now returns Result instead of panicking on bind failure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:12:36 +00:00
3f4e8effce fix: security hardening and data integrity for untrusted USB/IP clients
Critical fixes:
- Validate endpoint number is 0-15 (kernel parity: stub_rx.c)
- Cap in-flight URBs at 256 to prevent DoS resource exhaustion
- Replace expect() with graceful handling on lock contention in find_ep
- Use validated transfer_buffer_length for ISO allocation instead of
  unchecked multiplication of client-supplied values

High-priority fixes:
- Validate devid matches imported device in CMD_SUBMIT and CMD_UNLINK
- Fix string descriptor bLength u8 overflow for long strings (>126 chars)
- Use saturating_add for ISO actual_length sum, capped at transfer_buffer_length
- Truncate IN response data exceeding transfer_buffer_length

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:09:20 +00:00
a3dccbca9d Update flake.nix to allow nix flake check torun tests 2026-03-25 00:07:13 +00:00
d81f5826dc feat: add fc-vsock transport for Firecracker/Cloud-Hypervisor VMs
Support connecting to guests via Firecracker/Cloud-Hypervisor's Unix
domain socket vsock proxy. The host opens the VMM's socket file,
performs a CONNECT/OK text handshake, then uses the stream for USB/IP.

New address format: fc-vsock:/path/to/socket:<port>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 15:44:15 +00:00
4c368c02b5 feat: concurrent ISO pipelining via nusb update and &self handlers
Update nusb to c1380673 which allows multiple IsoEndpoint instances per
address, enabling concurrent URB submission from separate threads.

Change UsbInterfaceHandler trait methods from &mut self to &self and
replace Arc<Mutex<Box<dyn Handler>>> with Arc<dyn Handler>. This
removes the serialization bottleneck where the handler mutex was held
for the entire USB transfer duration, causing ISO audio to play at
~67% speed.

Handlers needing interior mutability (HID, CDC) now use Mutex on
individual fields. Passthrough handlers already used Arc<Mutex<>>
internally and need no changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 15:10:28 +00:00
9250c062aa fix: prevent idle disconnect by retrying interrupt IN and skipping
read timeout while URBs are in-flight

- Interrupt IN transfers now retry with 1s intervals (up to 5 min)
  instead of returning an error on timeout. Previously, nusb's 1s
  timeout caused a cancelled transfer error (-ENOENT) which told the
  kernel the endpoint was intentionally shut down, killing HID.
- Release the nusb Interface Mutex before blocking on interrupt and
  ISO transfers so other URBs on the same interface aren't starved.
- URB read timeout now skips when in-flight URBs exist (e.g. pending
  interrupt transfers), preventing false idle disconnects.
- Use appropriate timeouts per transfer type: interrupt=5min,
  isochronous=5s, control/bulk=1s.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:04:40 +00:00
b73b4b31f4 fix: ISO alt setting and actual_length for isochronous transfers
- Add set_alt_setting() to UsbInterfaceHandler trait so host passthrough
  handlers can update the physical USB interface's alternate setting via
  nusb::Interface::set_alt_setting() instead of raw control transfers.
  This allows nusb to find ISO endpoints after alt setting changes.
- Fix ISO OUT actual_length to equal the sum of per-packet actual_lengths
  instead of transfer_buffer_length. The kernel validates this invariant
  and disconnects the device on mismatch ("total length of iso packets
  not equal to actual length of buffer").

Enables successful USB Audio Class 2 isochronous playback through
host passthrough.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:45:55 +00:00
85146a12fe fix: passthrough descriptors, SET_INTERFACE forwarding, and error mapping
- Forward Configuration, BOS, and DeviceQualifier descriptors to the
  real device in passthrough mode, preserving IADs, class-specific
  descriptors (audio, HID, DFU), and endpoint companions
- Forward SET_INTERFACE to the physical device so alt settings are
  actually applied (critical for audio streaming)
- Round up interrupt IN buffers to max_packet_size (matching bulk IN)
- Map USB errors to proper Linux URB status codes: STALL→EPIPE(-32),
  cancelled→ENOENT(-2), timeout→ETIMEDOUT(-110)
- Propagate UrbResponse.status instead of hardcoding 0

Fixes USB Audio Class 2 device detection (kernel error "Audio class
v2/v3 interfaces need an interface association") and device reset
loops caused by EPROTO being returned for benign STALL/cancel errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:40:44 +00:00
02c3017679 Update README.md 2026-03-22 11:33:07 +00:00
63e9faf82d fix: align bulk IN buffers and forward unknown string descriptors
Two fixes for mass storage passthrough:

1. Bulk IN buffer allocation now rounds up to the endpoint's
   max_packet_size. nusb (and the USB spec) require IN transfers to be
   multiples of max_packet_size. Without this, SCSI INQUIRY (36 bytes on
   a 512-byte max_packet_size endpoint) was rejected, causing the kernel
   to repeatedly reset the device.

2. String descriptor requests for indices not in the local string pool
   are now forwarded to the device handler. This fixes interface and
   configuration string descriptors (e.g., iInterface=5) that exist on
   the real device but weren't populated in the synthetic string pool.

Tested: USB mass storage gadget via dummy_hcd successfully enumerates,
mounts, reads, and writes through the USBIP passthrough.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 11:13:45 +00:00
889017be3b fix: correct OUT actual_length, BCD encoding, and silent transfer failures
Three fixes for host device passthrough:

1. OUT transfers now report actual_length = transfer_buffer_length instead
   of 0. The kernel needs to know how many bytes were consumed; returning 0
   caused bulk writes (critical for mass storage) to appear as failures.

2. BCD version encoding (bcdUSB, bcdDevice) now properly reconstructs the
   full 2-byte BCD value from the Version struct's nibble fields. Previously,
   the minor field (a single nibble) was written as a full byte, corrupting
   values like USB 1.1 (0x0110 → 0x0101).

3. USB transfer handlers (nusb) now propagate errors instead of silently
   returning empty success responses. Failed control_in, bulk, and interrupt
   transfers were falling through to Ok(UrbResponse::default()), making the
   kernel think transfers succeeded with 0 bytes of data.

Also sets usb_version and dev_num from the actual device in build_usb_device.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 11:05:53 +00:00
f7236deba9 feat: add isochronous transfer support and fix host passthrough
Add IsoPacketDescriptor, UrbRequest, and UrbResponse types to the
protocol layer. Rewrite handle_urb_loop to a concurrent architecture
with pipelining for improved throughput. Replace interfaces vec with
InterfaceState to track alternate settings.

Implement isochronous transfer support in the nusb host handler with
structured ISO packet descriptor parsing and serialization. Switch to
ISO-capable nusb fork. Add IsoLoopbackHandler test fixture and ISO
transfer tests.

Fix host device passthrough: detach kernel drivers before claiming
interfaces, use real EP0 max packet size, forward SET_CONFIGURATION
to device, map nusb Speed enum to Linux kernel values, and use
extend_from_slice for OUT transfer buffers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 10:42:08 +00:00
09b8012f8c feat: add TCP transport support
Add TCP address types, parsing, and connect/listen functions alongside
the existing vsock transport. Update all CLI commands (client listen,
host connect, test_hid connect) to support both vsock: and tcp:
address prefixes. Add hostname resolution for TCP connections.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 10:41:59 +00:00
b66cd0f7e9 fix: harden protocol handling against panics and malicious input
Replace all unimplemented!() panics with proper error returns across
URB, HID, and host handlers. Replace assert!() panics with error
returns in response serialization and string pool. Validate direction
field at runtime instead of only in debug builds.

Add allocation bounds checks to read_from_socket, read timeout to
URB loop, and clamp transfer_buffer_length to u16::MAX for control
transfers. Use correct USB/IP error status codes in submit failure
responses. Propagate control OUT transfer errors instead of swallowing
them. Fix compilation errors and doc comment copy-paste issues.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 10:41:54 +00:00
30d3c9532e feat: add usbip-rs CLI tool with vsock transport
Convert to cargo workspace with lib/ and cli/ crates. Add Nix flake
for building and development. Extract handle_urb_loop and add
read_urb_command to the library for CLI consumption.

Implement the usbip-rs CLI binary with clap subcommands:
- client listen: accept incoming connections via vhci_hcd sysfs
- host connect: passthrough real USB devices via nusb
- test_hid connect: export a simulated HID keyboard for testing

Add vsock transport layer and vhci_hcd sysfs interaction module.
Apply rustfmt formatting project-wide and add rustfmt/clippy to devShell.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 10:41:42 +00:00
Jiajie Chen
0878920532 Release v0.8.0 2026-01-27 13:00:46 +08:00
Jiajie Chen
a19bfe8301 Simplify documentation (fixes #59)
Remove redundant sections from README and update LICENSE copyright year.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2025-12-25 20:58:48 +08:00
Jiajie Chen
c8cd214e1d Fix clippy warning: cloned_ref_to_slice_refs
Replace &[device.clone()] with std::slice::from_ref(&device) in
test to address clippy::cloned_ref_to_slice_refs warning.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2025-12-25 20:52:45 +08:00
Jiajie Chen
48d0d9ca34 Fix bus num on non-Linux platform 2025-12-24 23:23:25 +08:00
Jiajie Chen
b83f584391 Handle upper case in hid keyboard report 2025-12-24 23:18:11 +08:00
Jiajie Chen
fdbb9574aa Fix missing max packet size handling 2025-12-24 23:17:29 +08:00
Jiajie Chen
3ff5df5c2e Migrate to nusb 0.2.1 2025-12-24 23:17:02 +08:00
Jiajie Chen
156ec45a81 Apply more cargo clippy 2025-08-01 16:38:47 +08:00
Jiajie Chen
e14858f918 Apply cargo clippy 2025-08-01 16:35:06 +08:00