diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2026-08-30 13:52:49 -0700 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2026-09-20 12:52:10 -0700 |
| commit | 81d577c0c5c602cffb0e0c16cdbde9ffbc8bb1eb (patch) | |
| tree | 1ac9f22474bc4832f232a26bc8e4437ebdb90286 /drivers/input | |
| parent | e73972da25a81844b6f86ceaf4b27e280bfc219c (diff) | |
| download | linux-81d577c0c5c602cffb0e0c16cdbde9ffbc8bb1eb.tar.gz linux-81d577c0c5c602cffb0e0c16cdbde9ffbc8bb1eb.zip | |
Input: gscps2 - serialize hardware and buffer access in gscps2_flush()
gscps2_flush() reads from hardware registers and resets the ring buffer
indices ps2port->act and ps2port->append. In gscps2_enable(), the
trailing gscps2_flush() was called without holding ps2port->lock, racing
with concurrent hardware interrupts and buffer access.
Assert that ps2port->lock is held in gscps2_flush() with
lockdep_assert_held(), and ensure all callers acquire ps2port->lock so
that multi-step hardware sequences remain fully serialized without
unprotected windows.
Reported-by: sashiko-bot@kernel.org
Assisted-by: LLM
Link: https://patch.msgid.link/20260830-gscps2-v1-4-c733d4cae7f9@gmail.com
Acked-by: Helge Deller <deller@gmx.de>
Tested-by: Helge Deller <deller@gmx.de>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/serio/gscps2.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index fef6fffb6f86..36c25db9ff7f 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -228,6 +228,8 @@ static int wait_TBE(char __iomem *addr) */ static void gscps2_flush(struct gscps2port *ps2port) { + lockdep_assert_held(&ps2port->lock); + while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) gscps2_readb_input(ps2port->addr); ps2port->act = 0; @@ -364,7 +366,8 @@ static void gscps2_enable(struct gscps2port *ps2port, bool enable) } wait_TBE(ps2port->addr); - gscps2_flush(ps2port); + scoped_guard(spinlock_irqsave, &ps2port->lock) + gscps2_flush(ps2port); } /* @@ -551,7 +554,8 @@ static void __exit gscps2_remove(struct parisc_device *dev) serio_unregister_port(ps2port->port); free_irq(dev->irq, ps2port); - gscps2_flush(ps2port); + scoped_guard(spinlock_irqsave, &ps2port->lock) + gscps2_flush(ps2port); iounmap(ps2port->addr); #if 0 release_mem_region(dev->hpa, GSC_STATUS + 4); |
