Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25e14bf0 authored by Pietro Borrello's avatar Pietro Borrello Committed by Greg Kroah-Hartman
Browse files

HID: bigben: use spinlock to safely schedule workers



[ Upstream commit 76ca8da989c7d97a7f76c75d475fe95a584439d7 ]

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: 4eb1b01de5b9 ("HID: hid-bigbenff: fix race condition for scheduled work during removal")
Signed-off-by: default avatarPietro Borrello <borrello@diag.uniroma1.it>
Link: https://lore.kernel.org/r/20230125-hid-unregister-leds-v4-3-7860c5763c38@diag.uniroma1.it


Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 715edb01
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -185,6 +185,15 @@ struct bigben_device {
	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)
{
@@ -197,9 +206,6 @@ static void bigben_worker(struct work_struct *work)
	u32 len;
	unsigned long flags;

	if (bigben->removed)
		return;

	buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL);
	if (!buf)
		return;
@@ -285,7 +291,7 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
		bigben->work_ff = true;
		spin_unlock_irqrestore(&bigben->lock, flags);

		schedule_work(&bigben->worker);
		bigben_schedule_work(bigben);
	}

	return 0;
@@ -320,7 +326,7 @@ static void bigben_set_led(struct led_classdev *led,

			if (work) {
				bigben->work_led = true;
				schedule_work(&bigben->worker);
				bigben_schedule_work(bigben);
			}
			return;
		}
@@ -450,7 +456,7 @@ static int bigben_probe(struct hid_device *hid,
	bigben->left_motor_force = 0;
	bigben->work_led = 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");