Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID fixes from Jiri Kosina:

- fix for race condition that could lead to NULL pointer dereferences
or UAF during uhid device destruction (Jann Horn)

- contact count handling regression fixes for Wacom devices (Jason
Gerecke)

- fix for handling unnumbered HID reports handling in Google Vivaldi
driver (Dmitry Torokhov)

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
HID: wacom: Avoid using stale array indicies to read contact count
HID: wacom: Ignore the confidence flag when a touch is removed
HID: wacom: Reset expected and received contact counts at the same time
HID: uhid: Use READ_ONCE()/WRITE_ONCE() for ->running
HID: uhid: Fix worker destroying device without any protection
HID: vivaldi: Minor cleanups
HID: vivaldi: fix handling devices not using numbered reports
HID: Ignore battery for Elan touchscreen on HP Envy X360 15t-dr100

+105 -27
+1
drivers/hid/hid-ids.h
··· 400 400 #define USB_DEVICE_ID_HP_X2 0x074d 401 401 #define USB_DEVICE_ID_HP_X2_10_COVER 0x0755 402 402 #define I2C_DEVICE_ID_HP_ENVY_X360_15 0x2d05 403 + #define I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100 0x29CF 403 404 #define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817 404 405 #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544 405 406 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
+2
drivers/hid/hid-input.c
··· 330 330 HID_BATTERY_QUIRK_IGNORE }, 331 331 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15), 332 332 HID_BATTERY_QUIRK_IGNORE }, 333 + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100), 334 + HID_BATTERY_QUIRK_IGNORE }, 333 335 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15), 334 336 HID_BATTERY_QUIRK_IGNORE }, 335 337 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
+32 -9
drivers/hid/hid-vivaldi.c
··· 6 6 * Author: Sean O'Brien <seobrien@chromium.org> 7 7 */ 8 8 9 + #include <linux/device.h> 9 10 #include <linux/hid.h> 11 + #include <linux/kernel.h> 10 12 #include <linux/module.h> 13 + #include <linux/sysfs.h> 11 14 12 15 #define MIN_FN_ROW_KEY 1 13 16 #define MAX_FN_ROW_KEY 24 14 17 #define HID_VD_FN_ROW_PHYSMAP 0x00000001 15 18 #define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP) 16 - 17 - static struct hid_driver hid_vivaldi; 18 19 19 20 struct vivaldi_data { 20 21 u32 function_row_physmap[MAX_FN_ROW_KEY - MIN_FN_ROW_KEY + 1]; ··· 41 40 return size; 42 41 } 43 42 44 - DEVICE_ATTR_RO(function_row_physmap); 43 + static DEVICE_ATTR_RO(function_row_physmap); 45 44 static struct attribute *sysfs_attrs[] = { 46 45 &dev_attr_function_row_physmap.attr, 47 46 NULL ··· 75 74 struct hid_usage *usage) 76 75 { 77 76 struct vivaldi_data *drvdata = hid_get_drvdata(hdev); 77 + struct hid_report *report = field->report; 78 78 int fn_key; 79 79 int ret; 80 80 u32 report_len; 81 - u8 *buf; 81 + u8 *report_data, *buf; 82 82 83 83 if (field->logical != HID_USAGE_FN_ROW_PHYSMAP || 84 84 (usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL) ··· 91 89 if (fn_key > drvdata->max_function_row_key) 92 90 drvdata->max_function_row_key = fn_key; 93 91 94 - buf = hid_alloc_report_buf(field->report, GFP_KERNEL); 95 - if (!buf) 92 + report_data = buf = hid_alloc_report_buf(report, GFP_KERNEL); 93 + if (!report_data) 96 94 return; 97 95 98 - report_len = hid_report_len(field->report); 99 - ret = hid_hw_raw_request(hdev, field->report->id, buf, 96 + report_len = hid_report_len(report); 97 + if (!report->id) { 98 + /* 99 + * hid_hw_raw_request() will stuff report ID (which will be 0) 100 + * into the first byte of the buffer even for unnumbered 101 + * reports, so we need to account for this to avoid getting 102 + * -EOVERFLOW in return. 103 + * Note that hid_alloc_report_buf() adds 7 bytes to the size 104 + * so we can safely say that we have space for an extra byte. 105 + */ 106 + report_len++; 107 + } 108 + 109 + ret = hid_hw_raw_request(hdev, report->id, report_data, 100 110 report_len, HID_FEATURE_REPORT, 101 111 HID_REQ_GET_REPORT); 102 112 if (ret < 0) { ··· 117 103 goto out; 118 104 } 119 105 120 - ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, 106 + if (!report->id) { 107 + /* 108 + * Undo the damage from hid_hw_raw_request() for unnumbered 109 + * reports. 110 + */ 111 + report_data++; 112 + report_len--; 113 + } 114 + 115 + ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data, 121 116 report_len, 0); 122 117 if (ret) { 123 118 dev_warn(&hdev->dev, "failed to report feature %d\n",
+35 -14
drivers/hid/uhid.c
··· 28 28 29 29 struct uhid_device { 30 30 struct mutex devlock; 31 + 32 + /* This flag tracks whether the HID device is usable for commands from 33 + * userspace. The flag is already set before hid_add_device(), which 34 + * runs in workqueue context, to allow hid_add_device() to communicate 35 + * with userspace. 36 + * However, if hid_add_device() fails, the flag is cleared without 37 + * holding devlock. 38 + * We guarantee that if @running changes from true to false while you're 39 + * holding @devlock, it's still fine to access @hid. 40 + */ 31 41 bool running; 32 42 33 43 __u8 *rd_data; 34 44 uint rd_size; 35 45 46 + /* When this is NULL, userspace may use UHID_CREATE/UHID_CREATE2. */ 36 47 struct hid_device *hid; 37 48 struct uhid_event input_buf; 38 49 ··· 74 63 if (ret) { 75 64 hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret); 76 65 77 - hid_destroy_device(uhid->hid); 78 - uhid->hid = NULL; 79 - uhid->running = false; 66 + /* We used to call hid_destroy_device() here, but that's really 67 + * messy to get right because we have to coordinate with 68 + * concurrent writes from userspace that might be in the middle 69 + * of using uhid->hid. 70 + * Just leave uhid->hid as-is for now, and clean it up when 71 + * userspace tries to close or reinitialize the uhid instance. 72 + * 73 + * However, we do have to clear the ->running flag and do a 74 + * wakeup to make sure userspace knows that the device is gone. 75 + */ 76 + WRITE_ONCE(uhid->running, false); 77 + wake_up_interruptible(&uhid->report_wait); 80 78 } 81 79 } 82 80 ··· 194 174 spin_unlock_irqrestore(&uhid->qlock, flags); 195 175 196 176 ret = wait_event_interruptible_timeout(uhid->report_wait, 197 - !uhid->report_running || !uhid->running, 177 + !uhid->report_running || !READ_ONCE(uhid->running), 198 178 5 * HZ); 199 - if (!ret || !uhid->running || uhid->report_running) 179 + if (!ret || !READ_ONCE(uhid->running) || uhid->report_running) 200 180 ret = -EIO; 201 181 else if (ret < 0) 202 182 ret = -ERESTARTSYS; ··· 237 217 struct uhid_event *ev; 238 218 int ret; 239 219 240 - if (!uhid->running) 220 + if (!READ_ONCE(uhid->running)) 241 221 return -EIO; 242 222 243 223 ev = kzalloc(sizeof(*ev), GFP_KERNEL); ··· 279 259 struct uhid_event *ev; 280 260 int ret; 281 261 282 - if (!uhid->running || count > UHID_DATA_MAX) 262 + if (!READ_ONCE(uhid->running) || count > UHID_DATA_MAX) 283 263 return -EIO; 284 264 285 265 ev = kzalloc(sizeof(*ev), GFP_KERNEL); ··· 494 474 void *rd_data; 495 475 int ret; 496 476 497 - if (uhid->running) 477 + if (uhid->hid) 498 478 return -EALREADY; 499 479 500 480 rd_size = ev->u.create2.rd_size; ··· 576 556 577 557 static int uhid_dev_destroy(struct uhid_device *uhid) 578 558 { 579 - if (!uhid->running) 559 + if (!uhid->hid) 580 560 return -EINVAL; 581 561 582 - uhid->running = false; 562 + WRITE_ONCE(uhid->running, false); 583 563 wake_up_interruptible(&uhid->report_wait); 584 564 585 565 cancel_work_sync(&uhid->worker); 586 566 587 567 hid_destroy_device(uhid->hid); 568 + uhid->hid = NULL; 588 569 kfree(uhid->rd_data); 589 570 590 571 return 0; ··· 593 572 594 573 static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) 595 574 { 596 - if (!uhid->running) 575 + if (!READ_ONCE(uhid->running)) 597 576 return -EINVAL; 598 577 599 578 hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, ··· 604 583 605 584 static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev) 606 585 { 607 - if (!uhid->running) 586 + if (!READ_ONCE(uhid->running)) 608 587 return -EINVAL; 609 588 610 589 hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, ··· 616 595 static int uhid_dev_get_report_reply(struct uhid_device *uhid, 617 596 struct uhid_event *ev) 618 597 { 619 - if (!uhid->running) 598 + if (!READ_ONCE(uhid->running)) 620 599 return -EINVAL; 621 600 622 601 uhid_report_wake_up(uhid, ev->u.get_report_reply.id, ev); ··· 626 605 static int uhid_dev_set_report_reply(struct uhid_device *uhid, 627 606 struct uhid_event *ev) 628 607 { 629 - if (!uhid->running) 608 + if (!READ_ONCE(uhid->running)) 630 609 return -EINVAL; 631 610 632 611 uhid_report_wake_up(uhid, ev->u.set_report_reply.id, ev);
+35 -4
drivers/hid/wacom_wac.c
··· 2588 2588 } 2589 2589 } 2590 2590 2591 + static bool wacom_wac_slot_is_active(struct input_dev *dev, int key) 2592 + { 2593 + struct input_mt *mt = dev->mt; 2594 + struct input_mt_slot *s; 2595 + 2596 + if (!mt) 2597 + return false; 2598 + 2599 + for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { 2600 + if (s->key == key && 2601 + input_mt_get_value(s, ABS_MT_TRACKING_ID) >= 0) { 2602 + return true; 2603 + } 2604 + } 2605 + 2606 + return false; 2607 + } 2608 + 2591 2609 static void wacom_wac_finger_event(struct hid_device *hdev, 2592 2610 struct hid_field *field, struct hid_usage *usage, __s32 value) 2593 2611 { ··· 2656 2638 } 2657 2639 2658 2640 if (usage->usage_index + 1 == field->report_count) { 2659 - if (equivalent_usage == wacom_wac->hid_data.last_slot_field && 2660 - wacom_wac->hid_data.confidence) 2661 - wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); 2641 + if (equivalent_usage == wacom_wac->hid_data.last_slot_field) { 2642 + bool touch_removed = wacom_wac_slot_is_active(wacom_wac->touch_input, 2643 + wacom_wac->hid_data.id) && !wacom_wac->hid_data.tipswitch; 2644 + 2645 + if (wacom_wac->hid_data.confidence || touch_removed) { 2646 + wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); 2647 + } 2648 + } 2662 2649 } 2663 2650 } 2664 2651 ··· 2681 2658 wacom_wac->is_invalid_bt_frame = false; 2682 2659 2683 2660 hid_data->confidence = true; 2661 + 2662 + hid_data->cc_report = 0; 2663 + hid_data->cc_index = -1; 2664 + hid_data->cc_value_index = -1; 2684 2665 2685 2666 for (i = 0; i < report->maxfield; i++) { 2686 2667 struct hid_field *field = report->field[i]; ··· 2719 2692 hid_data->cc_index >= 0) { 2720 2693 struct hid_field *field = report->field[hid_data->cc_index]; 2721 2694 int value = field->value[hid_data->cc_value_index]; 2722 - if (value) 2695 + if (value) { 2723 2696 hid_data->num_expected = value; 2697 + hid_data->num_received = 0; 2698 + } 2724 2699 } 2725 2700 else { 2726 2701 hid_data->num_expected = wacom_wac->features.touch_max; 2702 + hid_data->num_received = 0; 2727 2703 } 2728 2704 } 2729 2705 ··· 2754 2724 2755 2725 input_sync(input); 2756 2726 wacom_wac->hid_data.num_received = 0; 2727 + wacom_wac->hid_data.num_expected = 0; 2757 2728 2758 2729 /* keep touch state for pen event */ 2759 2730 wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);