Summary
Fix recovery command transport corruption after an expected console bulk-read timeout.
irecv_usb_bulk_transfer() currently clears endpoint HALT after every negative libusb result. Recovery shell console draining normally ends with LIBUSB_ERROR_TIMEOUT; clearing HALT after that timeout can itself fail with EPROTO on newer iBoot and leave subsequent vendor control transfers failing.
This change:
- clears HALT only after
LIBUSB_ERROR_PIPE; - propagates control-OUT and control-IN failures instead of returning empty successful values;
- validates and terminates
getenvresponses safely; - dispatches CLI
getenvonce and reports failures on stderr; - preserves historical PIPE tolerance and expected disconnect semantics for
go,bootx,reboot, andmemboot; - preserves the legacy CPID
0x8900interrupt path and exact bare-commandbRequestselection; - adds focused tests for HALT handling, backend error mapping, teardown policy, and response finalization.
No public API or exported ABI is changed.
Reproduction and verification
Reproduced on Linux with libusb 1.0.30 and an iPhone 16e (iPhone17,5) running iBoot 13822.92.2.
Before the fix, the sequence was:
- Console bulk IN returns the banner.
- The next bulk IN ends with the expected timeout.
- libirecovery sends
CLEAR_FEATURE(ENDPOINT_HALT)despite the timeout. - iBoot rejects it with
EPROTO. - The following
getenvcontrol OUT/IN transfers fail, while the API reports an empty successful value.
With this branch, getenv auto-boot returns false through exactly one 17-byte command OUT and one six-byte response IN, with no clear-halt request or failed control transfer.
Verification performed:
- clean Autotools configure and build;
make check: 1/1 test passed;- live read-only
getenv auto-boottrace on the affected device; - default/libusb,
--without-tools, and--with-dummyconfigurations reviewed and built during compatibility review.
make distcheck remains gated by the existing NEWS not updated; not releasing release policy.
Compatibility boundaries
The Linux/libusb path and affected device were tested directly. Native Windows, IOKit, a genuine stalled endpoint on older hardware, and physical CPID 0x8900 hardware were not available for live testing. Their existing backend distinctions and legacy command path are preserved in the implementation and covered where possible by focused policy tests.