Skip to content

Commit 94109c9

Browse files
committed
Merge branch 'for-6.3/asus' into for-linus
UAF protection in work struct (Pietro Borrello)
2 parents 06db2af + 4ab3a08 commit 94109c9

File tree

1 file changed

+32
-5
lines changed

1 file changed

+32
-5
lines changed

drivers/hid/hid-asus.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct asus_kbd_leds {
9898
struct hid_device *hdev;
9999
struct work_struct work;
100100
unsigned int brightness;
101+
spinlock_t lock;
101102
bool removed;
102103
};
103104

@@ -490,33 +491,54 @@ static int rog_nkey_led_init(struct hid_device *hdev)
490491
return ret;
491492
}
492493

494+
static void asus_schedule_work(struct asus_kbd_leds *led)
495+
{
496+
unsigned long flags;
497+
498+
spin_lock_irqsave(&led->lock, flags);
499+
if (!led->removed)
500+
schedule_work(&led->work);
501+
spin_unlock_irqrestore(&led->lock, flags);
502+
}
503+
493504
static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
494505
enum led_brightness brightness)
495506
{
496507
struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
497508
cdev);
509+
unsigned long flags;
510+
511+
spin_lock_irqsave(&led->lock, flags);
498512
led->brightness = brightness;
499-
schedule_work(&led->work);
513+
spin_unlock_irqrestore(&led->lock, flags);
514+
515+
asus_schedule_work(led);
500516
}
501517

502518
static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev)
503519
{
504520
struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
505521
cdev);
522+
enum led_brightness brightness;
523+
unsigned long flags;
524+
525+
spin_lock_irqsave(&led->lock, flags);
526+
brightness = led->brightness;
527+
spin_unlock_irqrestore(&led->lock, flags);
506528

507-
return led->brightness;
529+
return brightness;
508530
}
509531

510532
static void asus_kbd_backlight_work(struct work_struct *work)
511533
{
512534
struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work);
513535
u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
514536
int ret;
537+
unsigned long flags;
515538

516-
if (led->removed)
517-
return;
518-
539+
spin_lock_irqsave(&led->lock, flags);
519540
buf[4] = led->brightness;
541+
spin_unlock_irqrestore(&led->lock, flags);
520542

521543
ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf));
522544
if (ret < 0)
@@ -584,6 +606,7 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
584606
drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set;
585607
drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get;
586608
INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work);
609+
spin_lock_init(&drvdata->kbd_backlight->lock);
587610

588611
ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev);
589612
if (ret < 0) {
@@ -1119,9 +1142,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
11191142
static void asus_remove(struct hid_device *hdev)
11201143
{
11211144
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
1145+
unsigned long flags;
11221146

11231147
if (drvdata->kbd_backlight) {
1148+
spin_lock_irqsave(&drvdata->kbd_backlight->lock, flags);
11241149
drvdata->kbd_backlight->removed = true;
1150+
spin_unlock_irqrestore(&drvdata->kbd_backlight->lock, flags);
1151+
11251152
cancel_work_sync(&drvdata->kbd_backlight->work);
11261153
}
11271154

0 commit comments

Comments
 (0)