Skip to content

Add missing sanity checks #727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 13, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length);
static hid_device *new_hid_device(void)
{
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
if (!dev)
return NULL;

dev->blocking = 1;

hidapi_thread_state_init(&dev->thread_state);
Expand Down
73 changes: 66 additions & 7 deletions linux/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,8 @@ static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct
/* If no top-level application collection is found and usage page/usage pair is found, pair is valid
https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections */
if (initial && usage_found && ctx->usage_page_found) {
*usage_page = ctx->usage_page;
return 0; /* success */
*usage_page = ctx->usage_page;
return 0; /* success */
}

return 1; /* finished processing */
Expand Down Expand Up @@ -448,6 +448,8 @@ static int get_hid_report_descriptor_from_sysfs(const char *sysfs_path, struct h
/* Construct <sysfs_path>/device/report_descriptor */
size_t rpt_path_len = strlen(sysfs_path) + 25 + 1;
char* rpt_path = (char*) calloc(1, rpt_path_len);
if (!rpt_path)
return -1;
snprintf(rpt_path, rpt_path_len, "%s/device/report_descriptor", sysfs_path);

res = get_hid_report_descriptor(rpt_path, rpt_desc);
Expand Down Expand Up @@ -784,7 +786,14 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device
}

/* Usage Page and Usage */
result = get_hid_report_descriptor_from_sysfs(sysfs_path, &report_desc);

if (sysfs_path) {
result = get_hid_report_descriptor_from_sysfs(sysfs_path, &report_desc);
}
else {
result = -1;
}

if (result >= 0) {
unsigned short page = 0, usage = 0;
struct hid_usage_iterator usage_iterator;
Expand All @@ -809,7 +818,7 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device
struct hid_device_info *prev_dev = cur_dev;

if (!tmp)
continue;
break;
cur_dev->next = tmp;
cur_dev = tmp;

Expand Down Expand Up @@ -854,6 +863,7 @@ static struct hid_device_info * create_device_info_for_hid_device(hid_device *de
/* Create the udev object */
udev = udev_new();
if (!udev) {
errno = ENOMEM;
register_device_error(dev, "Couldn't create udev context");
return NULL;
}
Expand All @@ -866,6 +876,7 @@ static struct hid_device_info * create_device_info_for_hid_device(hid_device *de

if (!root) {
/* TODO: have a better error reporting via create_device_info_for_device */
errno = EIO;
register_device_error(dev, "Couldn't create hid_device_info");
}

Expand Down Expand Up @@ -1061,6 +1072,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)

dev = new_hid_device();
if (!dev) {
errno = ENOMEM;
register_global_error("Couldn't allocate memory");
return NULL;
}
Expand All @@ -1073,8 +1085,8 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
/* Make sure this is a HIDRAW device - responds to HIDIOCGRDESCSIZE */
res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
if (res < 0) {
hid_close(dev);
register_global_error_format("ioctl(GRDESCSIZE) error for '%s', not a HIDRAW device?: %s", path, strerror(errno));
hid_close(dev);
return NULL;
}

Expand All @@ -1095,7 +1107,7 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t

if (!data || (length == 0)) {
errno = EINVAL;
register_device_error(dev, strerror(errno));
register_device_error(dev, "Zero buffer/length");
return -1;
}

Expand All @@ -1109,6 +1121,12 @@ int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t

int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
{
if (!data || (length == 0)) {
errno = EINVAL;
register_error_str(&dev->last_read_error_str, "Zero buffer/length");
return -1;
}

/* Set device error to none */
register_error_str(&dev->last_read_error_str, NULL);

Expand Down Expand Up @@ -1142,6 +1160,7 @@ int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t
indicate a device disconnection. */
if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
// We cannot use strerror() here as no -1 was returned from poll().
errno = EIO;
register_error_str(&dev->last_read_error_str, "hid_read_timeout: unexpected poll error (device disconnected)");
return -1;
}
Expand Down Expand Up @@ -1186,6 +1205,12 @@ int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char
{
int res;

if (!data || (length == 0)) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}

register_device_error(dev, NULL);

res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
Expand All @@ -1199,6 +1224,12 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data,
{
int res;

if (!data || (length == 0)) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}

register_device_error(dev, NULL);

res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
Expand All @@ -1212,6 +1243,12 @@ int HID_API_EXPORT HID_API_CALL hid_send_output_report(hid_device *dev, const un
{
int res;

if (!data || (length == 0)) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}

register_device_error(dev, NULL);

res = ioctl(dev->device_handle, HIDIOCSOUTPUT(length), data);
Expand All @@ -1225,6 +1262,12 @@ int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned c
{
int res;

if (!data || (length == 0)) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}

register_device_error(dev, NULL);

res = ioctl(dev->device_handle, HIDIOCGINPUT(length), data);
Expand Down Expand Up @@ -1253,6 +1296,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
{
if (!string || !maxlen) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}
Expand All @@ -1277,6 +1321,7 @@ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *st
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
{
if (!string || !maxlen) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}
Expand All @@ -1301,6 +1346,7 @@ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string,
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
{
if (!string || !maxlen) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}
Expand All @@ -1324,7 +1370,10 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s


HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) {
if (!dev->device_info) {
if (dev->device_info) {
register_device_error(dev, NULL);
}
else {
// Lazy initialize device_info
dev->device_info = create_device_info_for_hid_device(dev);
}
Expand All @@ -1339,6 +1388,7 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index
(void)string;
(void)maxlen;

errno = ENOSYS;
register_device_error(dev, "hid_get_indexed_string: not supported by hidraw");

return -1;
Expand All @@ -1348,6 +1398,15 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index
int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
{
struct hidraw_report_descriptor rpt_desc;

if (!buf || !buf_size) {
errno = EINVAL;
register_device_error(dev, "Zero buffer/length");
return -1;
}

register_device_error(dev, NULL);

int res = get_hid_report_descriptor_from_hidraw(dev, &rpt_desc);
if (res < 0) {
/* error already registered */
Expand Down
39 changes: 31 additions & 8 deletions mac/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char
register_device_error(dev, NULL);

if (!data || (length == 0)) {
register_device_error(dev, strerror(EINVAL));
register_device_error(dev, "Zero buffer/length");
return -1;
}

Expand Down Expand Up @@ -1149,6 +1149,11 @@ static int get_report(hid_device *dev, IOHIDReportType type, unsigned char *data

register_device_error(dev, NULL);

if (!data || (length == 0)) {
register_device_error(dev, "Zero buffer/length");
return -1;
}

if (report_id == 0x0) {
/* Not using numbered Reports.
Don't send the report number. */
Expand Down Expand Up @@ -1240,13 +1245,17 @@ static int cond_timedwait(hid_device *dev, pthread_cond_t *cond, pthread_mutex_t
}

return 0;

}

int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
{
int bytes_read = -1;

if (!data || (length == 0)) {
register_error_str(&dev->last_read_error_str, "Zero buffer/length");
return -1;
}

register_error_str(&dev->last_read_error_str, NULL);

/* Lock the access to the report list. */
Expand Down Expand Up @@ -1478,7 +1487,10 @@ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *s
}

HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) {
if (!dev->device_info) {
if (dev->device_info) {
register_device_error(dev, NULL);
}
else {
dev->device_info = create_device_info(dev->device_handle);
if (!dev->device_info) {
register_device_error(dev, "Failed to create hid_device_info");
Expand All @@ -1501,6 +1513,13 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index

int HID_API_EXPORT_CALL hid_darwin_get_location_id(hid_device *dev, uint32_t *location_id)
{
if (!location_id) {
register_device_error(dev, "Location ID is NULL");
return -1;
}

register_device_error(dev, NULL);

int res = get_int_property(dev->device_handle, CFSTR(kIOHIDLocationIDKey));
if (res != 0) {
*location_id = (uint32_t) res;
Expand All @@ -1523,23 +1542,27 @@ int HID_API_EXPORT_CALL hid_darwin_get_open_exclusive(void)

int HID_API_EXPORT_CALL hid_darwin_is_device_open_exclusive(hid_device *dev)
{
if (!dev)
return -1;

return (dev->open_options == kIOHIDOptionsTypeSeizeDevice) ? 1 : 0;
}

int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
{
if (!buf || !buf_size) {
register_device_error(dev, "Zero buffer/length");
return -1;
}

register_device_error(dev, NULL);

CFTypeRef ref = IOHIDDeviceGetProperty(dev->device_handle, CFSTR(kIOHIDReportDescriptorKey));
if (ref != NULL && CFGetTypeID(ref) == CFDataGetTypeID()) {
CFDataRef report_descriptor = (CFDataRef) ref;
const UInt8 *descriptor_buf = CFDataGetBytePtr(report_descriptor);
CFIndex descriptor_buf_len = CFDataGetLength(report_descriptor);
const CFIndex descriptor_buf_len = CFDataGetLength(report_descriptor);
size_t copy_len = (size_t) descriptor_buf_len;

if (descriptor_buf == NULL || descriptor_buf_len < 0) {
register_device_error(dev, "Zero buffer/length");
register_device_error(dev, "Zero descriptor from device");
return -1;
}

Expand Down
13 changes: 12 additions & 1 deletion windows/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1474,13 +1474,16 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *de
return 0;
}

HID_API_EXPORT struct hid_device_info * HID_API_CALL hid_get_device_info(hid_device *dev) {
HID_API_EXPORT struct hid_device_info * HID_API_CALL hid_get_device_info(hid_device *dev)
{
if (!dev->device_info)
{
register_string_error(dev, L"NULL device info");
return NULL;
}

register_string_error(dev, NULL);

return dev->device_info;
}

Expand Down Expand Up @@ -1565,10 +1568,18 @@ int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char
return -1;
}


int res = hid_winapi_descriptor_reconstruct_pp_data(pp_data, buf, buf_size);

HidD_FreePreparsedData(pp_data);

if (res == 0) {
register_string_error(dev, NULL);
}
else {
register_string_error(dev, L"Failed to reconstruct descriptor from PREPARSED_DATA");
}

return res;
}

Expand Down