Commit e58c88f0 authored by Minseong Kim's avatar Minseong Kim Committed by Dmitry Torokhov
Browse files

Input: lkkbd - disable pending work before freeing device



lkkbd_interrupt() schedules lk->tq via schedule_work(), and the work
handler lkkbd_reinit() dereferences the lkkbd structure and its
serio/input_dev fields.

lkkbd_disconnect() and error paths in lkkbd_connect() free the lkkbd
structure without preventing the reinit work from being queued again
until serio_close() returns. This can allow the work handler to run
after the structure has been freed, leading to a potential use-after-free.

Use disable_work_sync() instead of cancel_work_sync() to ensure the
reinit work cannot be re-queued, and call it both in lkkbd_disconnect()
and in lkkbd_connect() error paths after serio_open().

Signed-off-by: default avatarMinseong Kim <ii4gsp@gmail.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20251212052314.16139-1-ii4gsp@gmail.com


Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 429c4727
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -670,7 +670,8 @@ static int lkkbd_connect(struct serio *serio, struct serio_driver *drv)

	return 0;

 fail3:	serio_close(serio);
 fail3:	disable_work_sync(&lk->tq);
	serio_close(serio);
 fail2:	serio_set_drvdata(serio, NULL);
 fail1:	input_free_device(input_dev);
	kfree(lk);
@@ -684,6 +685,8 @@ static void lkkbd_disconnect(struct serio *serio)
{
	struct lkkbd *lk = serio_get_drvdata(serio);

	disable_work_sync(&lk->tq);

	input_get_device(lk->dev);
	input_unregister_device(lk->dev);
	serio_close(serio);