a1ien / rusb

A safe Rust wrapper for libusb.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Missing last byte from `read_control` on Windows 10

drbawb opened this issue · comments

Hi, I'm only a downstream user of rusb, but I'm having a problem with a library that relies on it. I'm using yubico-manager to interact with a yubikey, which is using rusb 0.8.1. (I did try updating the version of rusb it uses, which did not seem to have any change on the issue described below.) In summary on Windows the last byte of an 8-byte read is not being filled in resulting in a failure to communicate w/ the device under test. Whereas on Linux the same program reads a full 8 bytes from the device and the program operates as expected.

On manager.rs line 113 this program calls read_control to fill an 8-byte buffer. (Which it asserts must be exactly 8 bytes before even calling into rusb.) The last byte of the buffer that comes back is a flag register. This flag register very important to the functioning of this library & its communication with the device.

When I use this program on Windows to perform a challenge-response w/ the device it loops indefinitely because the last byte is never actually read. I added some tracing to the program which shows it is only getting 7 bytes as the result from calling Handle#read_control:

challenge: [2c, 36, ba, 98, 72, b8, c6, 6b, f7, ed, ca, a8, 1b, c0, 7e, f4, cf, d9, 21, a1, 0f, 2c, 38, 4f, 40, 44, 7a, 9e, e3, fb, 77, 0f, 26, 07, 53, 28, 2a, 84, 64, 81, 90, 9b, 50, d4, 70, 5e, f1, b0, 1b, 65, 24, 7d, 62, 54, 50, 45, 4e, 7d, 6c, d4, 08, 26, fc, 24]
challen len: 64
open device
write challenge
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
write packets
packet: [2c, 36, ba, 98, 72, b8, c6, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [6b, f7, ed, ca, a8, 1b, c0, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [7e, f4, cf, d9, 21, a1, 0f, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [2c, 38, 4f, 40, 44, 7a, 9e, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [e3, fb, 77, 0f, 26, 07, 53, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [28, 2a, 84, 64, 81, 90, 9b, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [50, d4, 70, 5e, f1, b0, 1b, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [65, 24, 7d, 62, 54, 50, 45, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [4e, 7d, 6c, d4, 08, 26, fc, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [24, 38, 30, 19, 00, 00, 00, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
done
wait response
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]
flags (7): [00, 05, 04, 03, 03, 07, 06, 00]

... and so on, this program never terminates because it's looking for the device to put 0x40 in the last byte.)

However the exact same program running under Linux properly reads 8-byte buffers from the device:

challenge: [2c, 36, ba, 98, 72, b8, c6, 6b, f7, ed, ca, a8, 1b, c0, 7e, f4, cf, d9, 21, a1, 0f, 2c, 38, 4f, 40, 44, 7a, 9e, e3, fb, 77, 0f, 26, 07, 53, 28, 2a, 84, 64, 81, 90, 9b, 50, d4, 70, 5e, f1, b0, 1b, 65, 24, 7d, 62, 54, 50, 45, 4e, 7d, 6c, d4, 08, 26, fc, 24]
challenge len: 64
open device
write challenge
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
write packets
packet: [2c, 36, ba, 98, 72, b8, c6, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [6b, f7, ed, ca, a8, 1b, c0, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [7e, f4, cf, d9, 21, a1, 0f, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [2c, 38, 4f, 40, 44, 7a, 9e, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [e3, fb, 77, 0f, 26, 07, 53, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [28, 2a, 84, 64, 81, 90, 9b, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [50, d4, 70, 5e, f1, b0, 1b, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [65, 24, 7d, 62, 54, 50, 45, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [4e, 7d, 6c, d4, 08, 26, fc, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
packet: [24, 38, 30, 19, 00, 00, 00, 00]
flags (8): [00, 05, 04, 03, 03, 07, 06, 00]
done
wait response
flags (8): [00, 05, 04, 03, 03, 07, fe, af]
flags (8): [00, 05, 04, 03, 03, 07, 06, af]
flags (8): [00, 05, 04, 03, 03, 07, 06, af]
flags (8): [00, 05, 04, 03, 03, 07, 06, af]
flags (8): [00, 05, 04, 03, 03, 07, 06, ae]
flags (8): [00, 05, 04, 03, 03, 07, 06, ae]
flags (8): [00, 05, 04, 03, 03, 07, 06, ae]
flags (8): [00, 05, 04, 03, 03, 07, 06, ae]

... snipped device waiting for physical input ... 

flags (8): [59, bf, 1b, 37, 08, 84, 74, c0]
flags (8): [00, 05, 04, 03, 03, 07, 10, 00]
crc response
digest: [d9, 6c, da, 35, 0a, f7, 50, 86, 9d, 17, 11, 12, 96, f4, 67, fb, d9, 2b, 18, 9a, c4, 45, d4, d5, 08, 61, df, 31, 6c, a3, 2d, 1f, 95, 3b, f0, 2c, af, b8, 0a, 09, 12, 14, bb, 7d, a7, 24, 5c, 2f, e0, cf, 74, b3, 2f, d5, 12, 30, d6, 8f, 87, a9, ca, 87, 4a, ed]
2WzaNQr3UIadFxESlvRn+9krGJrERdTVCGHfMWyjLR+VO/Asr7gKCRIUu32nJFwv4M90sy/VEjDWj4epyodK7Q
  • The device under test is a Yubico 5C NFC.
  • The programs I'm using downstream are open source and can be found at:
  • The Windows client is Windows 10 21H2 build 19044.1566
  • The Linux client is an up-to-date Arch Linux install w/ kernel 5.16.10
  • Both are using rustc 1.58.1 (db9d1b20b 2022-01-20)

Please let me know if there's any other details I could provide, thanks.

It's very strange behavior. Because read_control just wrapper around libusb. Do you use vendored libusb or libusb from vcpkg?
If you use vendored libusb try vcpkg

Also what compiller you use for windows msvc or mingw?

I am using the MSVC toolchain, and I do not have the vendored cargo feature turned on. I installed MSYS / the MinGW toolchain to try that and see the same results.

Do you know of an easy way to identify exactly what version of libusb is being linked / in-use? We could see what version I am running, perhaps it is out of date on this system.

If you not build libusb by you self troughs vcpkg that vendored version is used

I wrote a small test program that uses rusb 0.9 and libusb1-sys 0.6.0 (with MSVC toolchain) and this is what it says is being used on my system: libusb v1.0.24.11584

I actually found a list of bugs fixed upstream by libusb 1.0.25, and one of them sounds similar to what I've reported here: libusb/libusb#986

I will try to figure out how to get a newer version of libusb built for this platform and see if that resolves the issue.

In current master I have bump libusb to 1.0.25. So you can try cargo patch https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html

I manually built the latest commit (eb88e29) and linked it into this program, the behavior on Windows now lines up with I was seeing on the Linux box. Looks like all will be well w/ the next release of rusb, thanks for your help!

I think we can close this issue. Also note you can still install libusb through vcpkg and use current rusb release
In meaning time libusb upddate to 1.0.26 for regression fix. And I plan to make rusb release after 1.0.26