When hid_enumerate() iterates over the device list, it's possible
that libusb_open() fails. If this occurs on the next round after
a successful libusb_open() call, create_device_info_for_device()
is passed the previous iteration's already closed device handle.
Fix the crash by setting the handle to NULL after libusb_close().
- native implementations for hidraw/libusb/macOS;
- HID Report Descriptor reconstruction from HIDP_PREPARSED_DATA on Windows;
- unit-tests for some known devices for `hid_winapi_descriptor_reconstruct_pp_data`;
- support for ASAN builds (mainly to check the `hid_winapi_descriptor_reconstruct_pp_data`/its unit-tests;
- When `libusb_submit_transfer` in `read_thread` fails, `read_callback` never gets called and never sets `transfer_loop_finished` to true, causing `read_thread` to loop indefinitely;
- Do not attempt to run a read loop if the initial `libusb_submit_transfer` fails fixes the issue;
Fixes: #456
- pass the actual HID Report descriptor size (from HID descriptor);
- interface_num has to be wIndex, and not as part of wValue for LIBUSB_DT_REPORT request;
Potential execution path may happen if kernel driver successfully detached,
but libusb failed to claim the requested interface.
Otherwise the device remains with detached kernel driver.
- new API function: `struct hid_device_info * hid_get_device_info(hid_device *dev);` to get `hid_device_info` after the device already opened;
- reused existing implementation on Windows and macOS from enumeration routines to have the implementation;
- refactored libusb implementation to have a shared routine for `hid_enumerate` and `hid_get_device_info`;
- refactored hidraw implementation to have a shared routine for `hid_enumerate` and `hid_get_device_info`;
Resolves: #431Closes: #164Closes: #163
- by default find_file/find_library doesn't respect CFLAGS/LDFLAGS, and FindIconv fails to find Iconv;
- by explicitly trying to link against `-liconv` - we're checking if library is available in such way;
- additionally: if Iconv is detected as BUILT_IN, no need to explicitly depend on `Iconv::Iconv`;
- explicitly add Iconv as a dependent library;
- check if iconv requires pointer-to-const as input (introduce ICONV_CONST check);
- NetBSD CI (has external Iconv library implementation that uses all of the above);
Make buffer pointer NULL, once it is freed.
In hid_close() buffer pointer is freed and next to that the libusb_free_transfer function is called which checks for if the LIBUSB_TRANSFER_FREE_BUFFER flag is set and the buffer pointer is not NULL. when this condition evaluates true, it
tries to free memory for a buffer which is already free and a crash occurs.
Even though the described behavior should not happen as per libusb documentation, it has been observed with some version(s) of libusb.
In case if libusb_detach_kernel_driver fails inside hidapi_initialize_device
HIDAPI had tried to `libusb_close(dev->device_handle)` two times:
- right after `libusb_detach_kernel_driver`;
- outside of `hidapi_initialize_device` function;
The fix: `libusb_close` the device only once.
And since `hidapi_initialize_device` is not responsible for opening the device -
it is not responsible for closing it either.
Rationale: on Android one must use UsbManager, to access any
USB device. As a result, libraries like libusb can only use file descriptors
that are provided by UsbManager.
libusb has an API to use such file descriptors: hid_libusb_wrap_sys_device.
Having hid_libusb_wrap_sys_device currently is the only way to make hidapi
work on Android without root access and without custom Android builds.
Relevant info: https://github.com/libusb/libusb/pull/830/files
Read callback may fire itself on its own even after its been
requested to stop and exactly before the calling code
waits for its completion in indefinite loop.
Explicitly preventing re-fireing the submission loop,
fixes the issue.
Fixes: #142.
Signed-off-by: Ihor Dutchak <ihor.youw@gmail.com>
Make sure hid_device_info.serial_number is not null before passing it to
wcscmp().
When libusb can't open a device for any reason (e.g. file system
permissions), hid_device_info.serial_number is NULL. Make sure
hid_device_info.serial_number is not null before passing it to wcscmp(3).
Signed-off-by: Michael Hanselmann <public@hansmi.ch>
m4/ax_pthread.m4 says that PTHREAD_CFLAGS needs to be provided to the
linker line as well as the compile line. This enables static library
builds of hidapi.
While triaging libusb bugs, I took an indepth look at:
https://github.com/libusbx/libusbx/issues/25
This has lead me to the conclusion that there are 2 issues with hidapi's
libusb code wrt waiting for the transfer cancellation on read_thread()
exit:
1) There is a race where hid_close() can successfully cancel the transfer
after a read_callback() has submitted it but before read_thread() checks
shutdown_thread. If this race is hit, then the libusb_cancel_transfer()
in read_thread() will fail, causing read_thread() to not call
libusb_handle_events() to complete the cancelled transfer. hid_close()
will then free the transfer, and if later on libusb_handle_events() gets
called on the same context, it will try to complete the now freed
transfer. This is what I believe leads to the segfault described in
https://github.com/libusbx/libusbx/issues/25
2) hidapi uses one read_thread() per hid_device, so if there are multiple
hid_devices then there are multiple threads calling
libusb_handle_events(), in this case there is no guarantee that a single
libusb_handle_events() call will successfully lead to the cancelled
transfer being completed. If the transfer completion is already handled
by another read_thread() and there are no other events, then the
libusb_handle_events() call will hang, and thus the pthread_join() and
thus hidapi_close() will hang.
As number 2 is a generic problem found in more libusb apps, libusb has
gotten a new API called libusb_handle_events_completed(), which takes an
extra pointer to an int, whose contents must be set to nonzero on
completion by the callback, which allows waiting for the completion of a
specific transfer in a race-free manner.
This patch switches the waiting for the transfer's final completion to
using libusb_handle_events_completed(), thereby fixing both issues. Note
the while is necessary since libusb_handle_events_completed(), like
libusb_handle_events(), will return as soon as it has handled *any* event.
The difference with libusb_handle_events_completed() is that once it has
all the necessary internal libusb locks, it checks the contents of the
completed parameter, and will bail if that has become nonzero without
waiting for further events.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Some composite devices do not have bDeviceClass set to
LIBUSB_CLASS_PER_INTERFACE and were ignored when enumerating HID devices.
Ignore checking the bDeviceClass as we will be checking interface
bInterfaceClass later anyway.
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>