VYPR
Unrated severityNVD Advisory· Published May 28, 2026

CVE-2026-46202

CVE-2026-46202

Description

In the Linux kernel, the following vulnerability has been resolved:

HID: appletb-kbd: run inactivity autodim from workqueues

The autodim code in hid-appletb-kbd takes backlight_device->ops_lock via backlight_device_set_brightness() -> mutex_lock() from two different atomic contexts:

* appletb_inactivity_timer() is a struct timer_list callback, so it runs in softirq context. Every expiry triggers

BUG: sleeping function called from invalid context at kernel/locking/mutex.c:591 Call Trace:

__might_resched __mutex_lock backlight_device_set_brightness appletb_inactivity_timer call_timer_fn run_timer_softirq

* reset_inactivity_timer() is called from appletb_kbd_hid_event() and appletb_kbd_inp_event(). On real USB hardware these run in softirq/IRQ context (URB completion and input-event dispatch). When the Touch Bar has already been dimmed or turned off, the reset path calls backlight_device_set_brightness() directly to restore brightness, producing the same warning.

Both call sites hit the same mutex_lock()-from-atomic bug. Fix them together by moving the blocking work onto the system workqueue:

* Convert the inactivity timer from struct timer_list to struct delayed_work; the callback (appletb_inactivity_work) now runs in process context where mutex_lock() is legal. * Add a dedicated struct work_struct restore_brightness_work and have reset_inactivity_timer() schedule it instead of calling backlight_device_set_brightness() directly.

Cancel both works synchronously during driver tear-down alongside the existing backlight reference drop.

The semantics are unchanged (same delays, same state transitions on dim, turn-off and user activity); only the execution context of the sleeping call changes. The timer field and callback are renamed to match their new type; reset_inactivity_timer() keeps its name because it is invoked from input event paths that read naturally as "reset the inactivity timer".

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A sleeping function called from atomic context bug in the Apple Touch Bar keyboard driver's autodim code, fixed by moving work to workqueues.

Vulnerability

The hid-appletb-kbd driver in the Linux kernel contains a bug where the autodim code calls backlight_device_set_brightness(), which acquires a mutex, from two atomic contexts: the inactivity timer callback (softirq context) and the input event handlers (softirq/IRQ context on real USB hardware). This results in a BUG: sleeping function called from invalid context warning and potential kernel panic. The affected code paths are present in kernel versions prior to the fix commit 2473a334c292.

Exploitation

An attacker with physical access to a device equipped with an Apple Touch Bar can trigger the bug by allowing the inactivity timer to expire (dimming or turning off the backlight) or by generating input events (e.g., pressing keys or touching the Touch Bar) while the backlight is in a dimmed or off state. No special privileges are required beyond normal user interaction with the device.

Impact

Successful exploitation causes a kernel BUG warning and may lead to a denial of service (system crash or hang) due to the invalid context sleep. The bug does not appear to allow privilege escalation or information disclosure; the primary impact is availability.

Mitigation

The fix is included in Linux kernel commit 2473a334c292 ("HID: appletb-kbd: run inactivity autodim from workqueues"), which converts the timer to a delayed_work and adds a dedicated work struct for restoring brightness, ensuring all mutex operations occur in process context. Users should update to a kernel containing this commit or a backport. No workaround is available for unpatched kernels [1].

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

6
5c0830323689

HID: appletb-kbd: run inactivity autodim from workqueues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitSangyun KimApr 20, 2026Fixed in 6.18.32via kernel-cna
1 file changed · +30 15
  • drivers/hid/hid-appletb-kbd.c+30 15 modified
    diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
    index 711403441e3089..c96423a531f6f3 100644
    --- a/drivers/hid/hid-appletb-kbd.c
    +++ b/drivers/hid/hid-appletb-kbd.c
    @@ -17,7 +17,7 @@
     #include <linux/module.h>
     #include <linux/string.h>
     #include <linux/backlight.h>
    -#include <linux/timer.h>
    +#include <linux/workqueue.h>
     #include <linux/input/sparse-keymap.h>
     
     #include "hid-ids.h"
    @@ -62,7 +62,8 @@ struct appletb_kbd {
     	struct input_handle kbd_handle;
     	struct input_handle tpd_handle;
     	struct backlight_device *backlight_dev;
    -	struct timer_list inactivity_timer;
    +	struct delayed_work inactivity_work;
    +	struct work_struct restore_brightness_work;
     	bool has_dimmed;
     	bool has_turned_off;
     	u8 saved_mode;
    @@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
     	}
     }
     
    -static void appletb_inactivity_timer(struct timer_list *t)
    +static void appletb_inactivity_work(struct work_struct *work)
     {
    -	struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
    +	struct appletb_kbd *kbd = container_of(to_delayed_work(work),
    +					       struct appletb_kbd,
    +					       inactivity_work);
     
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (!kbd->has_dimmed) {
     			backlight_device_set_brightness(kbd->backlight_dev, 1);
     			kbd->has_dimmed = true;
    -			mod_timer(&kbd->inactivity_timer,
    -				jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
    +			mod_delayed_work(system_wq, &kbd->inactivity_work,
    +					 secs_to_jiffies(appletb_tb_idle_timeout));
     		} else if (!kbd->has_turned_off) {
     			backlight_device_set_brightness(kbd->backlight_dev, 0);
     			kbd->has_turned_off = true;
    @@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
     	}
     }
     
    +static void appletb_restore_brightness_work(struct work_struct *work)
    +{
    +	struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
    +					       restore_brightness_work);
    +
    +	if (kbd->backlight_dev)
    +		backlight_device_set_brightness(kbd->backlight_dev, 2);
    +}
    +
     static void reset_inactivity_timer(struct appletb_kbd *kbd)
     {
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (kbd->has_dimmed || kbd->has_turned_off) {
    -			backlight_device_set_brightness(kbd->backlight_dev, 2);
     			kbd->has_dimmed = false;
     			kbd->has_turned_off = false;
    +			schedule_work(&kbd->restore_brightness_work);
     		}
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     }
     
    @@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
     		dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
     	} else {
     		backlight_device_set_brightness(kbd->backlight_dev, 2);
    -		timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
    +		INIT_WORK(&kbd->restore_brightness_work,
    +			  appletb_restore_brightness_work);
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     
     	kbd->inp_handler.event = appletb_kbd_inp_event;
    @@ -444,7 +458,8 @@ close_hw:
     stop_hw:
     	hid_hw_stop(hdev);
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     	return ret;
    @@ -461,7 +476,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
     	hid_hw_stop(hdev);
     
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     }
    -- 
    cgit 1.3-korg
    
    
    
2473a334c292

HID: appletb-kbd: run inactivity autodim from workqueues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitSangyun KimApr 20, 2026Fixed in 7.0.9via kernel-cna
1 file changed · +30 15
  • drivers/hid/hid-appletb-kbd.c+30 15 modified
    diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
    index 8feac9e3589b83..462010a758993e 100644
    --- a/drivers/hid/hid-appletb-kbd.c
    +++ b/drivers/hid/hid-appletb-kbd.c
    @@ -17,7 +17,7 @@
     #include <linux/module.h>
     #include <linux/string.h>
     #include <linux/backlight.h>
    -#include <linux/timer.h>
    +#include <linux/workqueue.h>
     #include <linux/input/sparse-keymap.h>
     
     #include "hid-ids.h"
    @@ -62,7 +62,8 @@ struct appletb_kbd {
     	struct input_handle kbd_handle;
     	struct input_handle tpd_handle;
     	struct backlight_device *backlight_dev;
    -	struct timer_list inactivity_timer;
    +	struct delayed_work inactivity_work;
    +	struct work_struct restore_brightness_work;
     	bool has_dimmed;
     	bool has_turned_off;
     	u8 saved_mode;
    @@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
     	}
     }
     
    -static void appletb_inactivity_timer(struct timer_list *t)
    +static void appletb_inactivity_work(struct work_struct *work)
     {
    -	struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
    +	struct appletb_kbd *kbd = container_of(to_delayed_work(work),
    +					       struct appletb_kbd,
    +					       inactivity_work);
     
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (!kbd->has_dimmed) {
     			backlight_device_set_brightness(kbd->backlight_dev, 1);
     			kbd->has_dimmed = true;
    -			mod_timer(&kbd->inactivity_timer,
    -				jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
    +			mod_delayed_work(system_wq, &kbd->inactivity_work,
    +					 secs_to_jiffies(appletb_tb_idle_timeout));
     		} else if (!kbd->has_turned_off) {
     			backlight_device_set_brightness(kbd->backlight_dev, 0);
     			kbd->has_turned_off = true;
    @@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
     	}
     }
     
    +static void appletb_restore_brightness_work(struct work_struct *work)
    +{
    +	struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
    +					       restore_brightness_work);
    +
    +	if (kbd->backlight_dev)
    +		backlight_device_set_brightness(kbd->backlight_dev, 2);
    +}
    +
     static void reset_inactivity_timer(struct appletb_kbd *kbd)
     {
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (kbd->has_dimmed || kbd->has_turned_off) {
    -			backlight_device_set_brightness(kbd->backlight_dev, 2);
     			kbd->has_dimmed = false;
     			kbd->has_turned_off = false;
    +			schedule_work(&kbd->restore_brightness_work);
     		}
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     }
     
    @@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
     		dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
     	} else {
     		backlight_device_set_brightness(kbd->backlight_dev, 2);
    -		timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
    +		INIT_WORK(&kbd->restore_brightness_work,
    +			  appletb_restore_brightness_work);
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     
     	kbd->inp_handler.event = appletb_kbd_inp_event;
    @@ -444,7 +458,8 @@ close_hw:
     stop_hw:
     	hid_hw_stop(hdev);
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     	return ret;
    @@ -461,7 +476,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
     	hid_hw_stop(hdev);
     
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     }
    -- 
    cgit 1.3-korg
    
    
    
1654e53349d4

HID: appletb-kbd: run inactivity autodim from workqueues

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitSangyun KimApr 20, 2026Fixed in 7.1-rc4via kernel-cna
1 file changed · +30 15
  • drivers/hid/hid-appletb-kbd.c+30 15 modified
    diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
    index 8feac9e3589b83..462010a758993e 100644
    --- a/drivers/hid/hid-appletb-kbd.c
    +++ b/drivers/hid/hid-appletb-kbd.c
    @@ -17,7 +17,7 @@
     #include <linux/module.h>
     #include <linux/string.h>
     #include <linux/backlight.h>
    -#include <linux/timer.h>
    +#include <linux/workqueue.h>
     #include <linux/input/sparse-keymap.h>
     
     #include "hid-ids.h"
    @@ -62,7 +62,8 @@ struct appletb_kbd {
     	struct input_handle kbd_handle;
     	struct input_handle tpd_handle;
     	struct backlight_device *backlight_dev;
    -	struct timer_list inactivity_timer;
    +	struct delayed_work inactivity_work;
    +	struct work_struct restore_brightness_work;
     	bool has_dimmed;
     	bool has_turned_off;
     	u8 saved_mode;
    @@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
     	}
     }
     
    -static void appletb_inactivity_timer(struct timer_list *t)
    +static void appletb_inactivity_work(struct work_struct *work)
     {
    -	struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
    +	struct appletb_kbd *kbd = container_of(to_delayed_work(work),
    +					       struct appletb_kbd,
    +					       inactivity_work);
     
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (!kbd->has_dimmed) {
     			backlight_device_set_brightness(kbd->backlight_dev, 1);
     			kbd->has_dimmed = true;
    -			mod_timer(&kbd->inactivity_timer,
    -				jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
    +			mod_delayed_work(system_wq, &kbd->inactivity_work,
    +					 secs_to_jiffies(appletb_tb_idle_timeout));
     		} else if (!kbd->has_turned_off) {
     			backlight_device_set_brightness(kbd->backlight_dev, 0);
     			kbd->has_turned_off = true;
    @@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
     	}
     }
     
    +static void appletb_restore_brightness_work(struct work_struct *work)
    +{
    +	struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
    +					       restore_brightness_work);
    +
    +	if (kbd->backlight_dev)
    +		backlight_device_set_brightness(kbd->backlight_dev, 2);
    +}
    +
     static void reset_inactivity_timer(struct appletb_kbd *kbd)
     {
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (kbd->has_dimmed || kbd->has_turned_off) {
    -			backlight_device_set_brightness(kbd->backlight_dev, 2);
     			kbd->has_dimmed = false;
     			kbd->has_turned_off = false;
    +			schedule_work(&kbd->restore_brightness_work);
     		}
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     }
     
    @@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
     		dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
     	} else {
     		backlight_device_set_brightness(kbd->backlight_dev, 2);
    -		timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
    +		INIT_WORK(&kbd->restore_brightness_work,
    +			  appletb_restore_brightness_work);
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     
     	kbd->inp_handler.event = appletb_kbd_inp_event;
    @@ -444,7 +458,8 @@ close_hw:
     stop_hw:
     	hid_hw_stop(hdev);
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     	return ret;
    @@ -461,7 +476,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
     	hid_hw_stop(hdev);
     
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     }
    -- 
    cgit 1.3-korg
    
    
    
1654e53349d4

HID: appletb-kbd: run inactivity autodim from workqueues

1 file changed · +30 15
  • drivers/hid/hid-appletb-kbd.c+30 15 modified
    diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
    index 8feac9e3589b83..462010a758993e 100644
    --- a/drivers/hid/hid-appletb-kbd.c
    +++ b/drivers/hid/hid-appletb-kbd.c
    @@ -17,7 +17,7 @@
     #include <linux/module.h>
     #include <linux/string.h>
     #include <linux/backlight.h>
    -#include <linux/timer.h>
    +#include <linux/workqueue.h>
     #include <linux/input/sparse-keymap.h>
     
     #include "hid-ids.h"
    @@ -62,7 +62,8 @@ struct appletb_kbd {
     	struct input_handle kbd_handle;
     	struct input_handle tpd_handle;
     	struct backlight_device *backlight_dev;
    -	struct timer_list inactivity_timer;
    +	struct delayed_work inactivity_work;
    +	struct work_struct restore_brightness_work;
     	bool has_dimmed;
     	bool has_turned_off;
     	u8 saved_mode;
    @@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
     	}
     }
     
    -static void appletb_inactivity_timer(struct timer_list *t)
    +static void appletb_inactivity_work(struct work_struct *work)
     {
    -	struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
    +	struct appletb_kbd *kbd = container_of(to_delayed_work(work),
    +					       struct appletb_kbd,
    +					       inactivity_work);
     
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (!kbd->has_dimmed) {
     			backlight_device_set_brightness(kbd->backlight_dev, 1);
     			kbd->has_dimmed = true;
    -			mod_timer(&kbd->inactivity_timer,
    -				jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
    +			mod_delayed_work(system_wq, &kbd->inactivity_work,
    +					 secs_to_jiffies(appletb_tb_idle_timeout));
     		} else if (!kbd->has_turned_off) {
     			backlight_device_set_brightness(kbd->backlight_dev, 0);
     			kbd->has_turned_off = true;
    @@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
     	}
     }
     
    +static void appletb_restore_brightness_work(struct work_struct *work)
    +{
    +	struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
    +					       restore_brightness_work);
    +
    +	if (kbd->backlight_dev)
    +		backlight_device_set_brightness(kbd->backlight_dev, 2);
    +}
    +
     static void reset_inactivity_timer(struct appletb_kbd *kbd)
     {
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (kbd->has_dimmed || kbd->has_turned_off) {
    -			backlight_device_set_brightness(kbd->backlight_dev, 2);
     			kbd->has_dimmed = false;
     			kbd->has_turned_off = false;
    +			schedule_work(&kbd->restore_brightness_work);
     		}
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     }
     
    @@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
     		dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
     	} else {
     		backlight_device_set_brightness(kbd->backlight_dev, 2);
    -		timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
    +		INIT_WORK(&kbd->restore_brightness_work,
    +			  appletb_restore_brightness_work);
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     
     	kbd->inp_handler.event = appletb_kbd_inp_event;
    @@ -444,7 +458,8 @@ close_hw:
     stop_hw:
     	hid_hw_stop(hdev);
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     	return ret;
    @@ -461,7 +476,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
     	hid_hw_stop(hdev);
     
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     }
    -- 
    cgit 1.3-korg
    
    
    
2473a334c292

HID: appletb-kbd: run inactivity autodim from workqueues

1 file changed · +30 15
  • drivers/hid/hid-appletb-kbd.c+30 15 modified
    diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
    index 8feac9e3589b83..462010a758993e 100644
    --- a/drivers/hid/hid-appletb-kbd.c
    +++ b/drivers/hid/hid-appletb-kbd.c
    @@ -17,7 +17,7 @@
     #include <linux/module.h>
     #include <linux/string.h>
     #include <linux/backlight.h>
    -#include <linux/timer.h>
    +#include <linux/workqueue.h>
     #include <linux/input/sparse-keymap.h>
     
     #include "hid-ids.h"
    @@ -62,7 +62,8 @@ struct appletb_kbd {
     	struct input_handle kbd_handle;
     	struct input_handle tpd_handle;
     	struct backlight_device *backlight_dev;
    -	struct timer_list inactivity_timer;
    +	struct delayed_work inactivity_work;
    +	struct work_struct restore_brightness_work;
     	bool has_dimmed;
     	bool has_turned_off;
     	u8 saved_mode;
    @@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
     	}
     }
     
    -static void appletb_inactivity_timer(struct timer_list *t)
    +static void appletb_inactivity_work(struct work_struct *work)
     {
    -	struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
    +	struct appletb_kbd *kbd = container_of(to_delayed_work(work),
    +					       struct appletb_kbd,
    +					       inactivity_work);
     
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (!kbd->has_dimmed) {
     			backlight_device_set_brightness(kbd->backlight_dev, 1);
     			kbd->has_dimmed = true;
    -			mod_timer(&kbd->inactivity_timer,
    -				jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
    +			mod_delayed_work(system_wq, &kbd->inactivity_work,
    +					 secs_to_jiffies(appletb_tb_idle_timeout));
     		} else if (!kbd->has_turned_off) {
     			backlight_device_set_brightness(kbd->backlight_dev, 0);
     			kbd->has_turned_off = true;
    @@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
     	}
     }
     
    +static void appletb_restore_brightness_work(struct work_struct *work)
    +{
    +	struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
    +					       restore_brightness_work);
    +
    +	if (kbd->backlight_dev)
    +		backlight_device_set_brightness(kbd->backlight_dev, 2);
    +}
    +
     static void reset_inactivity_timer(struct appletb_kbd *kbd)
     {
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (kbd->has_dimmed || kbd->has_turned_off) {
    -			backlight_device_set_brightness(kbd->backlight_dev, 2);
     			kbd->has_dimmed = false;
     			kbd->has_turned_off = false;
    +			schedule_work(&kbd->restore_brightness_work);
     		}
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     }
     
    @@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
     		dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
     	} else {
     		backlight_device_set_brightness(kbd->backlight_dev, 2);
    -		timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
    +		INIT_WORK(&kbd->restore_brightness_work,
    +			  appletb_restore_brightness_work);
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     
     	kbd->inp_handler.event = appletb_kbd_inp_event;
    @@ -444,7 +458,8 @@ close_hw:
     stop_hw:
     	hid_hw_stop(hdev);
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     	return ret;
    @@ -461,7 +476,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
     	hid_hw_stop(hdev);
     
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     }
    -- 
    cgit 1.3-korg
    
    
    
5c0830323689

HID: appletb-kbd: run inactivity autodim from workqueues

1 file changed · +30 15
  • drivers/hid/hid-appletb-kbd.c+30 15 modified
    diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
    index 711403441e3089..c96423a531f6f3 100644
    --- a/drivers/hid/hid-appletb-kbd.c
    +++ b/drivers/hid/hid-appletb-kbd.c
    @@ -17,7 +17,7 @@
     #include <linux/module.h>
     #include <linux/string.h>
     #include <linux/backlight.h>
    -#include <linux/timer.h>
    +#include <linux/workqueue.h>
     #include <linux/input/sparse-keymap.h>
     
     #include "hid-ids.h"
    @@ -62,7 +62,8 @@ struct appletb_kbd {
     	struct input_handle kbd_handle;
     	struct input_handle tpd_handle;
     	struct backlight_device *backlight_dev;
    -	struct timer_list inactivity_timer;
    +	struct delayed_work inactivity_work;
    +	struct work_struct restore_brightness_work;
     	bool has_dimmed;
     	bool has_turned_off;
     	u8 saved_mode;
    @@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
     	}
     }
     
    -static void appletb_inactivity_timer(struct timer_list *t)
    +static void appletb_inactivity_work(struct work_struct *work)
     {
    -	struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
    +	struct appletb_kbd *kbd = container_of(to_delayed_work(work),
    +					       struct appletb_kbd,
    +					       inactivity_work);
     
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (!kbd->has_dimmed) {
     			backlight_device_set_brightness(kbd->backlight_dev, 1);
     			kbd->has_dimmed = true;
    -			mod_timer(&kbd->inactivity_timer,
    -				jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
    +			mod_delayed_work(system_wq, &kbd->inactivity_work,
    +					 secs_to_jiffies(appletb_tb_idle_timeout));
     		} else if (!kbd->has_turned_off) {
     			backlight_device_set_brightness(kbd->backlight_dev, 0);
     			kbd->has_turned_off = true;
    @@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
     	}
     }
     
    +static void appletb_restore_brightness_work(struct work_struct *work)
    +{
    +	struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
    +					       restore_brightness_work);
    +
    +	if (kbd->backlight_dev)
    +		backlight_device_set_brightness(kbd->backlight_dev, 2);
    +}
    +
     static void reset_inactivity_timer(struct appletb_kbd *kbd)
     {
     	if (kbd->backlight_dev && appletb_tb_autodim) {
     		if (kbd->has_dimmed || kbd->has_turned_off) {
    -			backlight_device_set_brightness(kbd->backlight_dev, 2);
     			kbd->has_dimmed = false;
     			kbd->has_turned_off = false;
    +			schedule_work(&kbd->restore_brightness_work);
     		}
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     }
     
    @@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
     		dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
     	} else {
     		backlight_device_set_brightness(kbd->backlight_dev, 2);
    -		timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
    -		mod_timer(&kbd->inactivity_timer,
    -			jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
    +		INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
    +		INIT_WORK(&kbd->restore_brightness_work,
    +			  appletb_restore_brightness_work);
    +		mod_delayed_work(system_wq, &kbd->inactivity_work,
    +				 secs_to_jiffies(appletb_tb_dim_timeout));
     	}
     
     	kbd->inp_handler.event = appletb_kbd_inp_event;
    @@ -444,7 +458,8 @@ close_hw:
     stop_hw:
     	hid_hw_stop(hdev);
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     	return ret;
    @@ -461,7 +476,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
     	hid_hw_stop(hdev);
     
     	if (kbd->backlight_dev) {
    -		timer_delete_sync(&kbd->inactivity_timer);
    +		cancel_delayed_work_sync(&kbd->inactivity_work);
    +		cancel_work_sync(&kbd->restore_brightness_work);
     		put_device(&kbd->backlight_dev->dev);
     	}
     }
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Calling a mutex-locking function (backlight_device_set_brightness) from atomic contexts (softirq timer callback and IRQ/softirq input-event paths) where sleeping is forbidden."

Attack vector

An attacker who can cause HID or input events on a system with an Apple Touch Bar keyboard can trigger the bug. When the Touch Bar's inactivity autodim feature (`appletb_tb_autodim`) is active, the timer callback `appletb_inactivity_timer()` fires in softirq context and calls `backlight_device_set_brightness()`, which tries to acquire a mutex — a sleeping operation illegal in atomic context. Similarly, user activity that resets the dim timer via `reset_inactivity_timer()` calls the same mutex-locked function from softirq/IRQ context (URB completion or input-event dispatch). Both paths produce a "BUG: sleeping function called from invalid context" splat and kernel warning [patch_id=2897799].

Affected code

The vulnerability is in `drivers/hid/hid-appletb-kbd.c` [patch_id=2897799]. The `appletb_inactivity_timer()` callback (a `struct timer_list` callback) and `reset_inactivity_timer()` (called from `appletb_kbd_hid_event()` and `appletb_kbd_inp_event()`) both call `backlight_device_set_brightness()`, which acquires a mutex, while running in atomic (softirq/IRQ) context.

What the fix does

The patch converts the `struct timer_list inactivity_timer` to a `struct delayed_work inactivity_work` and adds a new `struct work_struct restore_brightness_work` [patch_id=2897799]. The inactivity callback is renamed to `appletb_inactivity_work()` and runs on the system workqueue, where `mutex_lock()` is legal. `reset_inactivity_timer()` no longer calls `backlight_device_set_brightness()` directly; instead it schedules `restore_brightness_work` via `schedule_work()`. Both works are cancelled synchronously during driver removal via `cancel_delayed_work_sync()` and `cancel_work_sync()`. The same delays and state transitions are preserved; only the execution context changes from atomic to process context.

Preconditions

  • configThe Apple Touch Bar keyboard HID driver (hid-appletb-kbd) must be loaded and the backlight device must be present.
  • configThe inactivity autodim feature must be enabled (appletb_tb_autodim non-zero).
  • inputAn attacker must be able to trigger HID or input events (e.g., by physical USB access or by sending input events) to hit the reset path, or simply wait for the inactivity timer to expire.

Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.