[PATCH] Input: atkbd - fix UAF in atkbd_set_repeat_rate() on disconnect
From: Jeffin Philip <hidden>
Date: 2026-08-28 08:08:52
Also in:
lkml
Subsystem:
input (keyboard, mouse, joystick, touchscreen) drivers, the rest · Maintainers:
Dmitry Torokhov, Linus Torvalds
Commit 0ef7a26af127 ("Input: atkbd - fix canceling event_work in disconnect")
moved cancel_delayed_work_sync() after input_unregister_device() on
the premise that events may arrive until input_unregister_device returns.
However, this created a UAF as work that may have passed the
atkbd->enabled check in atkbd_event_work() may attempt to dereference dev
which is freed in input_unregister_device(). Reverting the commit also
does not solve the issue as events may still come through and pass the
atkbd->enabled check as atkbd_disable() and atkbd_event_work() guard with different
locks. Fix this by closing the hardware first using serio_close()
and then unregistering to prevent work from executing after
input_unregister_device(). serio_close() closes the device preventing
work from arriving.
Reported-by: syzbot+1e2ef9bcb29af666b2e6@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=1e2ef9bcb29af666b2e6
Fixes: 0ef7a26af127 ("Input: atkbd - fix canceling event_work in disconnect")
Signed-off-by: Jeffin Philip <redacted>
---
drivers/input/keyboard/atkbd.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 5736f4bc5a50..8874d9007a67 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c@@ -963,17 +963,18 @@ static void atkbd_disconnect(struct serio *serio) atkbd_disable(atkbd); - input_unregister_device(atkbd->dev); - /* - * Make sure we don't have a command in flight. - * Note that since atkbd->enabled is false event work will keep - * rescheduling itself until it gets canceled and will not try - * accessing freed input device or serio port. + * close serio first so device will not get any data, which prevents + * atkbd_event_work from being rescheduled after cancel_delayed_work_sync + * returns. This ensures no work can dereference atkbd->dev after it has + * been freed. */ - cancel_delayed_work_sync(&atkbd->event_work); serio_close(serio); + cancel_delayed_work_sync(&atkbd->event_work); + + input_unregister_device(atkbd->dev); + serio_set_drvdata(serio, NULL); kfree(atkbd); }
--
2.55.0