Input: psmouse - fix use-after-free during protocol disconnect

When a PS/2 mouse is disconnected or unbound, psmouse_disconnect() calls
the protocol disconnect handler (psmouse->disconnect()). During this time,
stray bytes arriving from the physical controller can still be passed to
psmouse_handle_byte(), which will invoke psmouse->protocol_handler().

This creates an asynchronous race condition with vendor disconnect handlers
(such as synaptics_disconnect()), which free vendor-specific private
structures (psmouse->private). If a byte arrives while the structures
are being freed, it leads to a use-after-free or NULL pointer
dereference in the protocol handler.

Fix this by explicitly setting psmouse->protocol_handler to NULL
safely wrapped in scoped_guard(serio_pause_rx, serio) immediately before
calling the vendor disconnect handler. We also add an unlikely check
in psmouse_handle_byte() to safely drop incoming bytes if the protocol
handler is NULL.

Assisted-by: Antigravity:gemini-3.5-flash
Link: https://patch.msgid.link/20260727050803.1269941-1-dmitry.torokhov@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
Dmitry Torokhov 2026-07-26 22:07:58 -07:00
parent 50411cada0
commit 761c2040a7

View File

@ -267,7 +267,15 @@ void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
*/
static int psmouse_handle_byte(struct psmouse *psmouse)
{
psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
psmouse_ret_t rc;
/* protocol_handler is NULL when device is being disconnected */
if (unlikely(!psmouse->protocol_handler)) {
psmouse->pktcnt = 0;
return 0;
}
rc = psmouse->protocol_handler(psmouse);
switch (rc) {
case PSMOUSE_BAD_DATA:
@ -1466,6 +1474,9 @@ static void psmouse_disconnect(struct serio *serio)
psmouse_deactivate(parent);
}
scoped_guard(serio_pause_rx, serio)
psmouse->protocol_handler = NULL;
if (psmouse->disconnect)
psmouse->disconnect(psmouse);