CVE-2026-46213
Description
In the Linux kernel, the following vulnerability has been resolved:
HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
Commit 38224c472a03 ("HID: appletb-kbd: fix slab use-after-free bug in appletb_kbd_probe") added timer_delete_sync(&kbd->inactivity_timer) to both the probe close_hw error path and appletb_kbd_remove(), but the way it was wired in left the inactivity timer reachable during driver tear-down via two distinct windows.
Window A -- put_device() before timer_delete_sync():
put_device(&kbd->backlight_dev->dev); timer_delete_sync(&kbd->inactivity_timer);
The inactivity_timer softirq reads kbd->backlight_dev and calls backlight_device_set_brightness() -> mutex_lock(&ops_lock). If a concurrent hid_appletb_bl unbind drops the last devm reference between these two calls, the backlight_device is freed and the mutex_lock() touches freed memory.
Window B -- backlight cleanup before hid_hw_stop():
if (kbd->backlight_dev) { timer_delete_sync(...); put_device(...); } hid_hw_close(hdev); hid_hw_stop(hdev);
Even after Window A is closed, hid_hw_close()/hid_hw_stop() still run afterwards, so a late ".event" callback from the HID core (USB URB completion on real Apple hardware) can arrive after timer_delete_sync() drained the softirq but before put_device() drops the reference. That callback reaches reset_inactivity_timer(), which calls mod_timer() and re-arms the timer. The freshly re-armed timer can then fire on the about-to-be-freed backlight_device.
Both windows produce the same KASAN slab-use-after-free:
BUG: KASAN: slab-use-after-free in __mutex_lock+0x1aab/0x21c0 Read of size 8 at addr ffff88803ee9a108 by task swapper/0/0 Call Trace:
__mutex_lock backlight_device_set_brightness appletb_inactivity_timer call_timer_fn run_timer_softirq handle_softirqs Allocated by task N: devm_backlight_device_register appletb_bl_probe Freed by task M: (concurrent hid_appletb_bl unbind path)
Close both windows at once by reworking the tear-down in appletb_kbd_remove() and in the probe close_hw error path so that
1) hid_hw_close()/hid_hw_stop() run before the backlight cleanup, guaranteeing no further .event callback can fire and re-arm the timer, and 2) inside the "if (kbd->backlight_dev)" block, timer_delete_sync() runs before put_device(), so the softirq is drained before the final reference is dropped.
Affected products
2Patches
659a79938ca55HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
1 file changed · +8 −9
drivers/hid/hid-appletb-kbd.c+8 −9 modifieddiff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index 0b10cff465e179..711403441e3089 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -440,13 +440,13 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id unregister_handler: input_unregister_handler(&kbd->inp_handler); close_hw: - if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); - timer_delete_sync(&kbd->inactivity_timer); - } hid_hw_close(hdev); stop_hw: hid_hw_stop(hdev); + if (kbd->backlight_dev) { + timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); + } return ret; } @@ -457,13 +457,13 @@ static void appletb_kbd_remove(struct hid_device *hdev) appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); input_unregister_handler(&kbd->inp_handler); + hid_hw_close(hdev); + hid_hw_stop(hdev); + if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); } - - hid_hw_close(hdev); - hid_hw_stop(hdev); } #ifdef CONFIG_PM -- cgit 1.3-korg
93d989e47bc3HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
1 file changed · +8 −9
drivers/hid/hid-appletb-kbd.c+8 −9 modifieddiff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index 0fdc0968b9ef26..8feac9e3589b83 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -440,13 +440,13 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id unregister_handler: input_unregister_handler(&kbd->inp_handler); close_hw: - if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); - timer_delete_sync(&kbd->inactivity_timer); - } hid_hw_close(hdev); stop_hw: hid_hw_stop(hdev); + if (kbd->backlight_dev) { + timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); + } return ret; } @@ -457,13 +457,13 @@ static void appletb_kbd_remove(struct hid_device *hdev) appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); input_unregister_handler(&kbd->inp_handler); + hid_hw_close(hdev); + hid_hw_stop(hdev); + if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); } - - hid_hw_close(hdev); - hid_hw_stop(hdev); } static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) -- cgit 1.3-korg
4db2af929279HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
1 file changed · +8 −9
drivers/hid/hid-appletb-kbd.c+8 −9 modifieddiff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index 0fdc0968b9ef26..8feac9e3589b83 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -440,13 +440,13 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id unregister_handler: input_unregister_handler(&kbd->inp_handler); close_hw: - if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); - timer_delete_sync(&kbd->inactivity_timer); - } hid_hw_close(hdev); stop_hw: hid_hw_stop(hdev); + if (kbd->backlight_dev) { + timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); + } return ret; } @@ -457,13 +457,13 @@ static void appletb_kbd_remove(struct hid_device *hdev) appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); input_unregister_handler(&kbd->inp_handler); + hid_hw_close(hdev); + hid_hw_stop(hdev); + if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); } - - hid_hw_close(hdev); - hid_hw_stop(hdev); } static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) -- cgit 1.3-korg
4db2af929279HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
1 file changed · +8 −9
drivers/hid/hid-appletb-kbd.c+8 −9 modifieddiff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index 0fdc0968b9ef26..8feac9e3589b83 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -440,13 +440,13 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id unregister_handler: input_unregister_handler(&kbd->inp_handler); close_hw: - if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); - timer_delete_sync(&kbd->inactivity_timer); - } hid_hw_close(hdev); stop_hw: hid_hw_stop(hdev); + if (kbd->backlight_dev) { + timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); + } return ret; } @@ -457,13 +457,13 @@ static void appletb_kbd_remove(struct hid_device *hdev) appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); input_unregister_handler(&kbd->inp_handler); + hid_hw_close(hdev); + hid_hw_stop(hdev); + if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); } - - hid_hw_close(hdev); - hid_hw_stop(hdev); } static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) -- cgit 1.3-korg
59a79938ca55HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
1 file changed · +8 −9
drivers/hid/hid-appletb-kbd.c+8 −9 modifieddiff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index 0b10cff465e179..711403441e3089 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -440,13 +440,13 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id unregister_handler: input_unregister_handler(&kbd->inp_handler); close_hw: - if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); - timer_delete_sync(&kbd->inactivity_timer); - } hid_hw_close(hdev); stop_hw: hid_hw_stop(hdev); + if (kbd->backlight_dev) { + timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); + } return ret; } @@ -457,13 +457,13 @@ static void appletb_kbd_remove(struct hid_device *hdev) appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); input_unregister_handler(&kbd->inp_handler); + hid_hw_close(hdev); + hid_hw_stop(hdev); + if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); } - - hid_hw_close(hdev); - hid_hw_stop(hdev); } #ifdef CONFIG_PM -- cgit 1.3-korg
93d989e47bc3HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
1 file changed · +8 −9
drivers/hid/hid-appletb-kbd.c+8 −9 modifieddiff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index 0fdc0968b9ef26..8feac9e3589b83 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -440,13 +440,13 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id unregister_handler: input_unregister_handler(&kbd->inp_handler); close_hw: - if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); - timer_delete_sync(&kbd->inactivity_timer); - } hid_hw_close(hdev); stop_hw: hid_hw_stop(hdev); + if (kbd->backlight_dev) { + timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); + } return ret; } @@ -457,13 +457,13 @@ static void appletb_kbd_remove(struct hid_device *hdev) appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF); input_unregister_handler(&kbd->inp_handler); + hid_hw_close(hdev); + hid_hw_stop(hdev); + if (kbd->backlight_dev) { - put_device(&kbd->backlight_dev->dev); timer_delete_sync(&kbd->inactivity_timer); + put_device(&kbd->backlight_dev->dev); } - - hid_hw_close(hdev); - hid_hw_stop(hdev); } static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Incorrect ordering of timer deletion, device put, and HID stop operations in the driver teardown path leaves the inactivity timer re-armed after it has been synchronously deleted, allowing a use-after-free of the backlight_device."
Attack vector
An attacker with physical access to a system using an Apple Touch Bar keyboard can trigger a use-after-free by causing a concurrent hid_appletb_bl unbind while the driver is being torn down [patch_id=2897707]. Window A occurs when put_device() is called before timer_delete_sync(), allowing a concurrent unbind to free the backlight_device between the two calls, after which the timer softirq accesses freed memory via mutex_lock() [patch_id=2897707]. Window B occurs because hid_hw_close()/hid_hw_stop() run after the timer is deleted, allowing a late HID .event callback (from USB URB completion) to re-arm the timer via reset_inactivity_timer(), which then fires on the about-to-be-freed backlight_device [patch_id=2897707]. Both windows manifest as a KASAN slab-use-after-free in __mutex_lock called from backlight_device_set_brightness via appletb_inactivity_timer [patch_id=2897707].
Affected code
The vulnerability is in drivers/hid/hid-appletb-kbd.c in the appletb_kbd_probe() close_hw error path and appletb_kbd_remove() function [patch_id=2897707]. Both functions had the inactivity timer deletion and backlight device put operations ordered incorrectly relative to each other and to hid_hw_close()/hid_hw_stop() [patch_id=2897707].
What the fix does
The patch reorders operations in both appletb_kbd_probe()'s close_hw error path and appletb_kbd_remove() to close both windows at once [patch_id=2897707]. First, hid_hw_close() and hid_hw_stop() are moved to execute before the backlight cleanup block, guaranteeing that no further HID .event callback can fire and re-arm the timer (closing Window B) [patch_id=2897707]. Second, within the backlight cleanup block, timer_delete_sync() is moved to run before put_device(), so the softirq is drained before the final reference is dropped (closing Window A) [patch_id=2897707].
Preconditions
- configSystem must have an Apple Touch Bar keyboard (HID device) with the hid-appletb-kbd driver loaded
- inputAttacker needs physical access to trigger USB URB completions or a concurrent hid_appletb_bl unbind
- inputDriver teardown must be in progress (device removal or probe failure)
Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.