Message ID | 20230511185252.386941-6-dmitry.torokhov@gmail.com |
---|---|
State | Accepted |
Commit | 7d674f9150c361e5b992551b46516d41eede3722 |
Headers | show |
Series | libps2: be more tolerant when processing commands | expand |
On Thu, May 11, 2023 at 11:52:45AM -0700, Dmitry Torokhov wrote: > When aborting PS/2 command the kernel should [re]set all flags before > waking up waiters, otherwise waiting thread may read obsolete values > of flags. > > Reported-by: Raul Rangel <rrangel@chromium.org> > Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> > --- > drivers/input/serio/libps2.c | 15 +++++++++++---- > 1 file changed, 11 insertions(+), 4 deletions(-) > > diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c > index 14b70a78875d..09eb605364bb 100644 > --- a/drivers/input/serio/libps2.c > +++ b/drivers/input/serio/libps2.c > @@ -478,15 +478,22 @@ bool ps2_handle_response(struct ps2dev *ps2dev, u8 data) > } > EXPORT_SYMBOL(ps2_handle_response); > > +/* > + * Clears state of PS/2 device after communication error by resetting majority > + * of flags and waking up waiters, if any. > + */ > void ps2_cmd_aborted(struct ps2dev *ps2dev) > { > - if (ps2dev->flags & PS2_FLAG_ACK) > + unsigned long old_flags = ps2dev->flags; > + > + /* reset all flags except last nak */ > + ps2dev->flags &= PS2_FLAG_NAK; > + > + if (old_flags & PS2_FLAG_ACK) > ps2dev->nak = 1; > > - if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) > + if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) > wake_up(&ps2dev->wait); > > - /* reset all flags except last nack */ > - ps2dev->flags &= PS2_FLAG_NAK; > } > EXPORT_SYMBOL(ps2_cmd_aborted); Reviewed-by: Raul E Rangel <rrangel@chromium.org>
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 14b70a78875d..09eb605364bb 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -478,15 +478,22 @@ bool ps2_handle_response(struct ps2dev *ps2dev, u8 data) } EXPORT_SYMBOL(ps2_handle_response); +/* + * Clears state of PS/2 device after communication error by resetting majority + * of flags and waking up waiters, if any. + */ void ps2_cmd_aborted(struct ps2dev *ps2dev) { - if (ps2dev->flags & PS2_FLAG_ACK) + unsigned long old_flags = ps2dev->flags; + + /* reset all flags except last nak */ + ps2dev->flags &= PS2_FLAG_NAK; + + if (old_flags & PS2_FLAG_ACK) ps2dev->nak = 1; - if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) + if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) wake_up(&ps2dev->wait); - /* reset all flags except last nack */ - ps2dev->flags &= PS2_FLAG_NAK; } EXPORT_SYMBOL(ps2_cmd_aborted);
When aborting PS/2 command the kernel should [re]set all flags before waking up waiters, otherwise waiting thread may read obsolete values of flags. Reported-by: Raul Rangel <rrangel@chromium.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> --- drivers/input/serio/libps2.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)