#168

Fix recovery command transport after console timeouts

Openfurbyhaxxwants to merge intofrom

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 getenv responses safely;
  • dispatches CLI getenv once and reports failures on stderr;
  • preserves historical PIPE tolerance and expected disconnect semantics for go, bootx, reboot, and memboot;
  • preserves the legacy CPID 0x8900 interrupt path and exact bare-command bRequest selection;
  • 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:

  1. Console bulk IN returns the banner.
  2. The next bulk IN ends with the expected timeout.
  3. libirecovery sends CLEAR_FEATURE(ENDPOINT_HALT) despite the timeout.
  4. iBoot rejects it with EPROTO.
  5. The following getenv control 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-boot trace on the affected device;
  • default/libusb, --without-tools, and --with-dummy configurations 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.