Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: synaptics - fix crash when enabling pass-through port

When enabling a pass-through port an interrupt might come before psmouse
driver binds to the pass-through port. However synaptics sub-driver
tries to access psmouse instance presumably associated with the
pass-through port to figure out if only 1 byte of response or entire
protocol packet needs to be forwarded to the pass-through port and may
crash if psmouse instance has not been attached to the port yet.

Fix the crash by introducing open() and close() methods for the port and
check if the port is open before trying to access psmouse instance.
Because psmouse calls serio_open() only after attaching psmouse instance
to serio port instance this prevents the potential crash.

Reported-by: Takashi Iwai <tiwai@suse.de>
Fixes: 100e16959c3c ("Input: libps2 - attach ps2dev instances as serio port's drvdata")
Link: https://bugzilla.suse.com/show_bug.cgi?id=1219522
Cc: stable@vger.kernel.org
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/Z4qSHORvPn7EU2j1@google.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

+43 -14
+42 -14
drivers/input/mouse/synaptics.c
··· 665 665 priv->pt_port = NULL; 666 666 } 667 667 668 + static int synaptics_pt_open(struct serio *serio) 669 + { 670 + struct psmouse *parent = psmouse_from_serio(serio->parent); 671 + struct synaptics_data *priv = parent->private; 672 + 673 + guard(serio_pause_rx)(parent->ps2dev.serio); 674 + priv->pt_port_open = true; 675 + 676 + return 0; 677 + } 678 + 679 + static void synaptics_pt_close(struct serio *serio) 680 + { 681 + struct psmouse *parent = psmouse_from_serio(serio->parent); 682 + struct synaptics_data *priv = parent->private; 683 + 684 + guard(serio_pause_rx)(parent->ps2dev.serio); 685 + priv->pt_port_open = false; 686 + } 687 + 668 688 static int synaptics_is_pt_packet(u8 *buf) 669 689 { 670 690 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; 671 691 } 672 692 673 - static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet) 693 + static void synaptics_pass_pt_packet(struct synaptics_data *priv, u8 *packet) 674 694 { 675 - struct psmouse *child = psmouse_from_serio(ptport); 695 + struct serio *ptport; 676 696 677 - if (child && child->state == PSMOUSE_ACTIVATED) { 678 - serio_interrupt(ptport, packet[1], 0); 679 - serio_interrupt(ptport, packet[4], 0); 680 - serio_interrupt(ptport, packet[5], 0); 681 - if (child->pktsize == 4) 682 - serio_interrupt(ptport, packet[2], 0); 683 - } else { 684 - serio_interrupt(ptport, packet[1], 0); 697 + ptport = priv->pt_port; 698 + if (!ptport) 699 + return; 700 + 701 + serio_interrupt(ptport, packet[1], 0); 702 + 703 + if (priv->pt_port_open) { 704 + struct psmouse *child = psmouse_from_serio(ptport); 705 + 706 + if (child->state == PSMOUSE_ACTIVATED) { 707 + serio_interrupt(ptport, packet[4], 0); 708 + serio_interrupt(ptport, packet[5], 0); 709 + if (child->pktsize == 4) 710 + serio_interrupt(ptport, packet[2], 0); 711 + } 685 712 } 686 713 } 687 714 ··· 747 720 serio->write = synaptics_pt_write; 748 721 serio->start = synaptics_pt_start; 749 722 serio->stop = synaptics_pt_stop; 723 + serio->open = synaptics_pt_open; 724 + serio->close = synaptics_pt_close; 750 725 serio->parent = psmouse->ps2dev.serio; 751 726 752 727 psmouse->pt_activate = synaptics_pt_activate; ··· 1245 1216 1246 1217 if (SYN_CAP_PASS_THROUGH(priv->info.capabilities) && 1247 1218 synaptics_is_pt_packet(psmouse->packet)) { 1248 - if (priv->pt_port) 1249 - synaptics_pass_pt_packet(priv->pt_port, 1250 - psmouse->packet); 1251 - } else 1219 + synaptics_pass_pt_packet(priv, psmouse->packet); 1220 + } else { 1252 1221 synaptics_process_packet(psmouse); 1222 + } 1253 1223 1254 1224 return PSMOUSE_FULL_PACKET; 1255 1225 }
+1
drivers/input/mouse/synaptics.h
··· 188 188 bool disable_gesture; /* disable gestures */ 189 189 190 190 struct serio *pt_port; /* Pass-through serio port */ 191 + bool pt_port_open; 191 192 192 193 /* 193 194 * Last received Advanced Gesture Mode (AGM) packet. An AGM packet