CVE-2025-38016
Publication date:
18/06/2025
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
HID: bpf: abort dispatch if device destroyed<br />
<br />
The current HID bpf implementation assumes no output report/request will<br />
go through it after hid_bpf_destroy_device() has been called. This leads<br />
to a bug that unplugging certain types of HID devices causes a cleaned-<br />
up SRCU to be accessed. The bug was previously a hidden failure until a<br />
recent x86 percpu change [1] made it access not-present pages.<br />
<br />
The bug will be triggered if the conditions below are met:<br />
<br />
A) a device under the driver has some LEDs on<br />
B) hid_ll_driver->request() is uninplemented (e.g., logitech-djreceiver)<br />
<br />
If condition A is met, hidinput_led_worker() is always scheduled *after*<br />
hid_bpf_destroy_device().<br />
<br />
hid_destroy_device<br />
` hid_bpf_destroy_device<br />
` cleanup_srcu_struct(&hdev->bpf.srcu)<br />
` hid_remove_device<br />
` ...<br />
` led_classdev_unregister<br />
` led_trigger_set(led_cdev, NULL)<br />
` led_set_brightness(led_cdev, LED_OFF)<br />
` ...<br />
` input_inject_event<br />
` input_event_dispose<br />
` hidinput_input_event<br />
` schedule_work(&hid->led_work) [hidinput_led_worker]<br />
<br />
This is fine when condition B is not met, where hidinput_led_worker()<br />
calls hid_ll_driver->request(). This is the case for most HID drivers,<br />
which implement it or use the generic one from usbhid. The driver itself<br />
or an underlying driver will then abort processing the request.<br />
<br />
Otherwise, hidinput_led_worker() tries hid_hw_output_report() and leads<br />
to the bug.<br />
<br />
hidinput_led_worker<br />
` hid_hw_output_report<br />
` dispatch_hid_bpf_output_report<br />
` srcu_read_lock(&hdev->bpf.srcu)<br />
` srcu_read_unlock(&hdev->bpf.srcu, idx)<br />
<br />
The bug has existed since the introduction [2] of<br />
dispatch_hid_bpf_output_report(). However, the same bug also exists in<br />
dispatch_hid_bpf_raw_requests(), and I&#39;ve reproduced (no visible effect<br />
because of the lack of [1], but confirmed bpf.destroyed == 1) the bug<br />
against the commit (i.e., the Fixes:) introducing the function. This is<br />
because hidinput_led_worker() falls back to hid_hw_raw_request() when<br />
hid_ll_driver->output_report() is uninplemented (e.g., logitech-<br />
djreceiver).<br />
<br />
hidinput_led_worker<br />
` hid_hw_output_report: -ENOSYS<br />
` hid_hw_raw_request<br />
` dispatch_hid_bpf_raw_requests<br />
` srcu_read_lock(&hdev->bpf.srcu)<br />
` srcu_read_unlock(&hdev->bpf.srcu, idx)<br />
<br />
Fix the issue by returning early in the two mentioned functions if<br />
hid_bpf has been marked as destroyed. Though<br />
dispatch_hid_bpf_device_event() handles input events, and there is no<br />
evidence that it may be called after the destruction, the same check, as<br />
a safety net, is also added to it to maintain the consistency among all<br />
dispatch functions.<br />
<br />
The impact of the bug on other architectures is unclear. Even if it acts<br />
as a hidden failure, this is still dangerous because it corrupts<br />
whatever is on the address calculated by SRCU. Thus, CC&#39;ing the stable<br />
list.<br />
<br />
[1]: commit 9d7de2aa8b41 ("x86/percpu/64: Use relative percpu offsets")<br />
[2]: commit 9286675a2aed ("HID: bpf: add HID-BPF hooks for<br />
hid_hw_output_report")
Severity CVSS v4.0: Pending analysis
Last modification:
18/06/2025