Input: lkkbd - disable pending work before freeing device
commit e58c88f0cb2d8ed89de78f6f17409d29cfab6c5c upstream. 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: Minseong Kim <ii4gsp@gmail.com> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251212052314.16139-1-ii4gsp@gmail.com Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
40e3042de4
commit
cffc4e29b1
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue