lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251108045609.26338-1-duoming@zju.edu.cn>
Date: Sat,  8 Nov 2025 12:56:09 +0800
From: Duoming Zhou <duoming@....edu.cn>
To: linux-input@...r.kernel.org
Cc: linux-kernel@...r.kernel.org,
	dmitry.torokhov@...il.com,
	kuba@...nel.org,
	alexander.deucher@....com,
	pali@...nel.org,
	hverkuil+cisco@...nel.org,
	akpm@...ux-foundation.org,
	andriy.shevchenko@...ux.intel.com,
	tglx@...utronix.de,
	mingo@...nel.org,
	Jonathan.Cameron@...wei.com,
	Duoming Zhou <duoming@....edu.cn>
Subject: [PATCH] Input: psmouse - fix use-after-free bugs due to rescheduled delayed works

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
resync_work and dev3_register_work could be rescheduled again, resulting
in the following two use-after-free scenarios:

1. The psmouse structure is deallocated in psmouse_disconnect(), while
resync_work remains active and attempts to dereference the already
freed psmouse in psmouse_resync().

CPU 0                   | CPU 1
psmouse_disconnect()    | psmouse_receive_byte()
                        |   if(psmouse->state == ...)
  psmouse_set_state()   |
  flush_workqueue()     |
                        |   psmouse_queue_work() //reschedule
  kfree(psmouse); //FREE|
                        | psmouse_resync()
                        |   psmouse = container_of(); //USE
                        |   psmouse-> //USE

2. The alps_data structure is deallocated in alps_disconnect(), while
dev3_register_work remains active and attempts to dereference the
already freed alps_data inside alps_register_bare_ps2_mouse().

CPU 0                   | CPU 1
psmouse_disconnect()    | alps_process_byte()
  flush_workqueue()     |   alps_report_bare_ps2_packet()
                        |   psmouse_queue_work() //reschedule
  alps_disconnect()     |
                        | alps_register_bare_ps2_mouse()
    kfree(priv); //FREE |
                        |   priv = container_of(); //USE
                        |   priv-> //USE

Replace flush_workqueue() with disable_delayed_work_sync(), and also
add disable_delayed_work_sync() in alps_disconnect(). This ensures
that both resync_work and dev3_register_work are properly canceled
and prevented from being rescheduled before the psmouse and alps_data
structures are deallocated.

These bugs are identified by static analysis.

Fixes: f0d5c6f419d3 ("Input: psmouse - attempt to re-synchronize mouse every 5 seconds")
Fixes: 04aae283ba6a ("Input: ALPS - do not mix trackstick and external PS/2 mouse data")
Signed-off-by: Duoming Zhou <duoming@....edu.cn>
---
 drivers/input/mouse/alps.c         | 1 +
 drivers/input/mouse/psmouse-base.c | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

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))
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 77ea7da3b1c..eb41c553e80 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1484,7 +1484,7 @@ static void psmouse_disconnect(struct serio *serio)
 
 	/* make sure we don't have a resync in progress */
 	mutex_unlock(&psmouse_mutex);
-	flush_workqueue(kpsmoused_wq);
+	disable_delayed_work_sync(&psmouse->resync_work);
 	mutex_lock(&psmouse_mutex);
 
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ