HID: bigben: use spinlock to safely schedule workers
[ Upstream commit76ca8da989] Use spinlocks to deal with workers introducing a wrapper bigben_schedule_work(), and several spinlock checks. Otherwise, bigben_set_led() may schedule bigben->worker after the structure has been freed, causing a use-after-free. Fixes:4eb1b01de5("HID: hid-bigbenff: fix race condition for scheduled work during removal") Signed-off-by: Pietro Borrello <borrello@diag.uniroma1.it> Link: https://lore.kernel.org/r/20230125-hid-unregister-leds-v4-3-7860c5763c38@diag.uniroma1.it Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ec8b79668e
commit
fddde36316
@@ -185,6 +185,15 @@ struct bigben_device {
|
|||||||
struct work_struct worker;
|
struct work_struct worker;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void bigben_schedule_work(struct bigben_device *bigben)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&bigben->lock, flags);
|
||||||
|
if (!bigben->removed)
|
||||||
|
schedule_work(&bigben->worker);
|
||||||
|
spin_unlock_irqrestore(&bigben->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static void bigben_worker(struct work_struct *work)
|
static void bigben_worker(struct work_struct *work)
|
||||||
{
|
{
|
||||||
@@ -197,9 +206,6 @@ static void bigben_worker(struct work_struct *work)
|
|||||||
u32 len;
|
u32 len;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (bigben->removed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL);
|
buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return;
|
return;
|
||||||
@@ -285,7 +291,7 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
|
|||||||
bigben->work_ff = true;
|
bigben->work_ff = true;
|
||||||
spin_unlock_irqrestore(&bigben->lock, flags);
|
spin_unlock_irqrestore(&bigben->lock, flags);
|
||||||
|
|
||||||
schedule_work(&bigben->worker);
|
bigben_schedule_work(bigben);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -320,7 +326,7 @@ static void bigben_set_led(struct led_classdev *led,
|
|||||||
|
|
||||||
if (work) {
|
if (work) {
|
||||||
bigben->work_led = true;
|
bigben->work_led = true;
|
||||||
schedule_work(&bigben->worker);
|
bigben_schedule_work(bigben);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -450,7 +456,7 @@ static int bigben_probe(struct hid_device *hid,
|
|||||||
bigben->left_motor_force = 0;
|
bigben->left_motor_force = 0;
|
||||||
bigben->work_led = true;
|
bigben->work_led = true;
|
||||||
bigben->work_ff = true;
|
bigben->work_ff = true;
|
||||||
schedule_work(&bigben->worker);
|
bigben_schedule_work(bigben);
|
||||||
|
|
||||||
hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
|
hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user