Re: [PATCH] Input: synaptics - add transparent pass-through mode for TrackPoint
[email protected] Sun, 09 Aug 2026 06:09:29 +0000
| Newsgroups | org.kernel.vger.linux-input |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: New issues: - [Critical] Missing pass-through port check in psmouse_receive_byte causes type confusion and control flow hijacking for non-psmouse parent ports. - [High] Blind cast of pass-through port's drvdata in synaptics_set_transparent_mode leads to type confusion and NULL pointer dereferences. - [Medium] Hardware and software states become permanently desynchronized if the guest port is stopped while transparent mode is active. - [Medium] Unprotected updates to protocol_handler and pktsize in synaptics_set_transparent_mode() cause a data race with the RX interrupt. - [Medium] Skipping synaptics_set_mode() during reconnect in transparent mode leaves the hardware uninitialized when transparent mode is later disabled. Pre-existing issues: - [High] Failing to create sysfs attributes leaks the pass-through port and causes a use-after-free on its access. -- --- Patch [1]: [PATCH] Input: synaptics - add transparent pass-through mode for TrackPoint --- commit 1fc824e1e4a325dcff29e0fb66487d7ede60f009 Author: Laserology OSS <[email protected]> Subject: Input: synaptics - add transparent pass-through mode for TrackPoint This patch adds a transparent pass-through mode for Synaptics touchpads with a pass-through port. It allows the guest device to run at its full poll rate while temporarily disabling the touchpad. Link: https://lore.kernel.org/all/[email protected]/ > diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c > --- a/drivers/input/mouse/psmouse-base.c > +++ b/drivers/input/mouse/psmouse-base.c [ ... ] > @@ -392,8 +392,18 @@ static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data) > } > > if (psmouse->packet[1] == PSMOUSE_RET_ID) { > + struct serio *serio = ps2dev->serio; > + struct psmouse *parent_psmouse = NULL; > + > __psmouse_set_state(psmouse, PSMOUSE_IGNORE); > - serio_reconnect(ps2dev->serio); > + /* Some devices need parent to be reconnected instead */ > + if (serio->parent) > + parent_psmouse = psmouse_from_serio(serio->parent); > + if (parent_psmouse && parent_psmouse->pt_reconnect_parent && > + parent_psmouse->pt_reconnect_parent(parent_psmouse)) [Severity: Critical] Is it safe to unconditionally cast serio->parent's driver data to a psmouse struct here? If the parent port is a multiplexer driven by ps2mult, its driver data would be a different struct. Accessing parent_psmouse->pt_reconnect_parent could then lead to type confusion and read a bogus function pointer, potentially causing a crash or arbitrary execution when called. > + serio_reconnect(serio->parent); > + else > + serio_reconnect(serio); > return; > } > > diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c > --- a/drivers/input/mouse/synaptics.c > +++ b/drivers/input/mouse/synaptics.c [ ... ] > @@ -672,6 +750,8 @@ static void synaptics_pt_stop(struct serio *serio) > > guard(serio_pause_rx)(parent->ps2dev.serio); > priv->pt_port = NULL; > + > + synaptics_update_protocol_handler(parent); [Severity: Medium] If the guest port is unbound while transparent mode is active, priv->pt_port becomes NULL and synaptics_update_protocol_handler() will revert the software handler to synaptics_process_byte. Will this cause the hardware and software states to become permanently desynchronized? The hardware would still be in transparent mode sending 3-byte packets, but the software would expect 6-byte absolute packets, which could lead to erratic pointer behavior. > } [ ... ] > @@ -1438,6 +1535,80 @@ PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL, [ ... ] > + WRITE_ONCE(priv->transparent_mode, value); > + > + synaptics_update_protocol_handler(psmouse); [Severity: Medium] Should this call to synaptics_update_protocol_handler() be protected by guard(serio_pause_rx)? It updates psmouse->protocol_handler and psmouse->pktsize outside of the lock. If an interrupt arrives concurrently, psmouse_receive_byte() might read the new pktsize but the old protocol_handler, leading to incorrect packet processing. > + > + /* > + * The touchpad is stopped for the duration of the mode switch, but the > + * pass-through guest keeps streaming. It may therefore be left with a > + * partially assembled packet from the previous mode. Drop it so the > + * stream restarts cleanly in the new mode and no stale bytes are > + * misparsed as pointer motion or spurious button clicks. > + */ > + if (READ_ONCE(priv->pt_port)) { > + struct psmouse *child = psmouse_from_serio(priv->pt_port); > + > + if (child && child->state == PSMOUSE_ACTIVATED) > + psmouse_set_state(child, PSMOUSE_ACTIVATED); > + } [Severity: High] Does this cast safely handle the case where the guest port is unbound or bound to a different driver? If the port is unbound, the drvdata is NULL and psmouse_from_serio() evaluates to a negative offset, causing a panic when child->state is checked. If it is bound to another driver like serio_raw, this causes type confusion and psmouse_set_state() could dereference an invalid pointer, leading to memory corruption. > + > + return len; > +} [ ... ] > @@ -1478,8 +1655,16 @@ static int synaptics_reconnect(struct psmouse *psmouse) > */ > ssleep(1); > } > - ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID); > - error = synaptics_detect(psmouse, 0); > + if (READ_ONCE(priv->transparent_mode) && READ_ONCE(priv->pt_port)) { > + error = synaptics_enter_transparent_mode(psmouse); > + if (!error) { > + serio_reconnect(priv->pt_port); > + return 0; > + } [Severity: Medium] Returning early here bypasses the normal synaptics_set_mode() initialization during reconnect. If the user later disables transparent mode via sysfs, synaptics_exit_transparent_mode() only restores the previous mode byte but won't re-enable Advanced Gesture Mode or other configurations set up by synaptics_set_mode(). Could this leave the touchpad uninitialized after a suspend/resume cycle? > + } else { > + ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID); > + error = synaptics_detect(psmouse, 0); > + } > } while (error && ++retry < 3); [ ... ] > @@ -1691,9 +1869,26 @@ static int synaptics_init_ps2(struct psmouse *psmouse, [ ... ] > init_fail: > + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->info.identity)) > + device_remove_file(&psmouse->ps2dev.serio->dev, > + &psmouse_attr_disable_gesture.dattr); > + if (SYN_CAP_PASS_THROUGH(priv->info.capabilities)) > + device_remove_file(&psmouse->ps2dev.serio->dev, > + &psmouse_attr_transparent_mode.dattr); > kfree(priv); > return err; > } [Severity: High] This isn't a bug introduced by this patch, but if device_create_file() fails in synaptics_init_ps2(), the code jumps to init_fail, frees the priv structure, and returns an error without unregistering the pass-through serio child port. The child port remains active, and any subsequent interaction with it could trigger callbacks that dereference the freed parent->private pointer, resulting in a use-after-free. Should the port be unregistered during cleanup? -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1