[PATCH v2 RESEND 1/2] Input: alps - fix use-after-free bugs caused by dev3_register_work

Duoming Zhou posted 2 patches 1 day, 12 hours ago
[PATCH v2 RESEND 1/2] Input: alps - fix use-after-free bugs caused by dev3_register_work
Posted by Duoming Zhou 1 day, 12 hours ago
The dev3_register_work delayed work item is initialized within
alps_reconnect() and scheduled upon receipt of the first bare
PS/2 packet from an external PS/2 device connected to the ALPS
touchpad. During device detachment, the original implementation
calls flush_workqueue() in psmouse_disconnect() to ensure
completion of dev3_register_work. However, the flush_workqueue()
in psmouse_disconnect() only blocks and waits for work items that
were already queued to the workqueue prior to its invocation. Any
work items submitted after flush_workqueue() is called are not
included in the set of tasks that the flush operation awaits.
This means that after flush_workqueue() has finished executing,
the dev3_register_work could still be scheduled. Although the
psmouse state is set to PSMOUSE_CMD_MODE in psmouse_disconnect(),
the scheduling of dev3_register_work remains unaffected.

The race condition can occur as follows:

CPU 0 (cleanup path)     | CPU 1 (delayed work)
psmouse_disconnect()     |
  psmouse_set_state()    |
  flush_workqueue()      | alps_report_bare_ps2_packet()
  alps_disconnect()      |   psmouse_queue_work()
    kfree(priv); // FREE | alps_register_bare_ps2_mouse()
                         |   priv = container_of(work...); // USE
                         |   priv->dev3 // USE

Add disable_delayed_work_sync() in alps_disconnect() to ensure
that dev3_register_work is properly canceled and prevented from
executing after the alps_data structure has been deallocated.

This bug is identified by static analysis.

Fixes: 04aae283ba6a ("Input: ALPS - do not mix trackstick and external PS/2 mouse data")
Cc: stable@kernel.org
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
---
Changes in v2:
  - Split the original patch into two separate patches (alps and psmouse-base).

 drivers/input/mouse/alps.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index d0cb9fb9482..df8953a5196 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -2975,6 +2975,7 @@ static void alps_disconnect(struct psmouse *psmouse)
 
 	psmouse_reset(psmouse);
 	timer_shutdown_sync(&priv->timer);
+	disable_delayed_work_sync(&priv->dev3_register_work);
 	if (priv->dev2)
 		input_unregister_device(priv->dev2);
 	if (!IS_ERR_OR_NULL(priv->dev3))
-- 
2.34.1
Re: [PATCH v2 RESEND 1/2] Input: alps - fix use-after-free bugs caused by dev3_register_work
Posted by Dmitry Torokhov 20 hours ago
On Wed, Dec 17, 2025 at 11:00:17AM +0800, Duoming Zhou wrote:
> The dev3_register_work delayed work item is initialized within
> alps_reconnect() and scheduled upon receipt of the first bare
> PS/2 packet from an external PS/2 device connected to the ALPS
> touchpad. During device detachment, the original implementation
> calls flush_workqueue() in psmouse_disconnect() to ensure
> completion of dev3_register_work. However, the flush_workqueue()
> in psmouse_disconnect() only blocks and waits for work items that
> were already queued to the workqueue prior to its invocation. Any
> work items submitted after flush_workqueue() is called are not
> included in the set of tasks that the flush operation awaits.
> This means that after flush_workqueue() has finished executing,
> the dev3_register_work could still be scheduled. Although the
> psmouse state is set to PSMOUSE_CMD_MODE in psmouse_disconnect(),
> the scheduling of dev3_register_work remains unaffected.
> 
> The race condition can occur as follows:
> 
> CPU 0 (cleanup path)     | CPU 1 (delayed work)
> psmouse_disconnect()     |
>   psmouse_set_state()    |
>   flush_workqueue()      | alps_report_bare_ps2_packet()
>   alps_disconnect()      |   psmouse_queue_work()
>     kfree(priv); // FREE | alps_register_bare_ps2_mouse()
>                          |   priv = container_of(work...); // USE
>                          |   priv->dev3 // USE
> 
> Add disable_delayed_work_sync() in alps_disconnect() to ensure
> that dev3_register_work is properly canceled and prevented from
> executing after the alps_data structure has been deallocated.
> 
> This bug is identified by static analysis.
> 
> Fixes: 04aae283ba6a ("Input: ALPS - do not mix trackstick and external PS/2 mouse data")
> Cc: stable@kernel.org
> Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>

Applied, thank you.

-- 
Dmitry