Re: [PATCH 1/2] serdev: fix race between tty-port unregister and in-flight callbacks
Markus Probst <[email protected]> Fri, 31 Jul 2026 12:43:06 +0000
| Newsgroups | org.kernel.vger.linux-serial,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
--=-mx5cNm777Bf9oKHRXlOr Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, 2026-07-31 at 14:01 +0200, Greg Kroah-Hartman wrote: > On Fri, Jul 31, 2026 at 11:30:53AM +0000, Markus Probst wrote: > > On Fri, 2026-07-31 at 10:06 +0200, Greg Kroah-Hartman wrote: > > > From: Joshua Rogers <[email protected]> > > >=20 > > > serdev_tty_port_unregister() clears port->client_data and frees the > > > controller without synchronizing with in-flight flip buffer work. > > > This can cause NULL pointer dereferences or use-after-free if > > > ttyport_receive_buf() or ttyport_write_wakeup() runs concurrently. > > >=20 > > > Add cancel_work_sync() to drain pending buffer work before clearing > > > state, and add NULL checks for client_data in both callbacks as > > > secondary hardening. > > >=20 > > > Assisted-by: AISLE:Snapshot > > > Cc: stable <[email protected]> > > > Signed-off-by: Joshua Rogers <[email protected]> > > > Signed-off-by: Greg Kroah-Hartman <[email protected]> > > > --- > > > drivers/tty/serdev/serdev-ttyport.c | 15 +++++++++++++-- > > > 1 file changed, 13 insertions(+), 2 deletions(-) > > >=20 > > > diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev= /serdev-ttyport.c > > > index bab1b143b8a6..48ce5b3f8308 100644 > > > --- a/drivers/tty/serdev/serdev-ttyport.c > > > +++ b/drivers/tty/serdev/serdev-ttyport.c > > > @@ -26,9 +26,14 @@ static size_t ttyport_receive_buf(struct tty_port = *port, const u8 *cp, > > > const u8 *fp, size_t count) > > > { > > > struct serdev_controller *ctrl =3D port->client_data; > > > - struct serport *serport =3D serdev_controller_get_drvdata(ctrl); > > > + struct serport *serport; > > > size_t ret; > > > =20 > > > + if (!ctrl) > > > + return 0; > > > + > > > + serport =3D serdev_controller_get_drvdata(ctrl); > > > + > > > if (!test_bit(SERPORT_ACTIVE, &serport->flags)) > > > return 0; > > > =20 > > > @@ -46,9 +51,14 @@ static size_t ttyport_receive_buf(struct tty_port = *port, const u8 *cp, > > > static void ttyport_write_wakeup(struct tty_port *port) > > > { > > > struct serdev_controller *ctrl =3D port->client_data; > > > - struct serport *serport =3D serdev_controller_get_drvdata(ctrl); > > > + struct serport *serport; > > > struct tty_struct *tty; > > > =20 > > > + if (!ctrl) > > > + return; > > > + > > > + serport =3D serdev_controller_get_drvdata(ctrl); > > > + > > > tty =3D tty_port_tty_get(port); > > > if (!tty) > > > return; > > > @@ -312,6 +322,7 @@ int serdev_tty_port_unregister(struct tty_port *p= ort) > > > return -ENODEV; > > > =20 > > > serdev_controller_remove(ctrl); > > > + cancel_work_sync(&port->buf.work); > > > port->client_data =3D NULL; > > > port->client_ops =3D &tty_port_default_client_ops; > > > serdev_controller_put(ctrl); > >=20 > > So why exactly does tty keep calling `receive_buf` and `write_wakeup` > > with the tty port closed? > >=20 > > After `serdev_controller_remove` is called, the tty port should already > > be closed by the drivers. >=20 > Are you sure? remove can be called by a device removal, while close > might be coming from a different code path (like it is in userspace.) >=20 > If this is impossible, as close will ALWAYS happen before remove, then > it's not an issue, but that is probably not the case, right? The driver *should* always close the serdev device on remove if previously opened. Thus the existence of `devm_serdev_device_open`. The serdev subsystem itself does not guarantee that it has been called. I just took a look at every driver using `serdev_device_open` (non devm), and every one seems to call `serdev_device_close` on remove. Assuming `cancel_work_sync(&port->buf.work);` is used correctly here, we could still take the patch for hardening. Thanks - Markus Probst >=20 > thanks, >=20 > greg k-h --=-mx5cNm777Bf9oKHRXlOr Content-Type: application/pgp-signature; name="signature.asc" Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEEgnQYxPSsWOdyMMRzNHYf+OetQ9IFAmpsmEobFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyAAoJEDR2H/jnrUPSPnoP/0cy0RT9oHV7SXZFZtha c1nq/y1RcBgmcbNulJ06C2nBg7uT21PzKOzFuhXEMQg8JeLen0LVNhTjad8+Ma5h pMRVZLf48NqikqnbsMqhtM0b8SSFGsVtUL8HVvaDepyxP4r0FpGkggtm2aGts6ON fqkAAiV1xKMcbjNNS9x1MfVNMvqgfI47Fau4yyVKu8nT3BQaaCSYPwaNbTUOVIkY A8hU1E8VExVfkl/GiqXsbeF9HCwcE3twg3ZEBm+7P9398cGq3DuX5RYRrZK+PNl2 1RNarJRoK1Hkuz411gL492QHkqw97eLMj9qBWdQRt2xWUgRV7AM4YUUQ47otxc+0 3XZ5c+THK7saEzc5rhQ5Etss3YUnz4+xWmXlf2Yku7XJGujThfqct2hEl7mUQMtD EfTmTTdpB3FsLrruxpTkAiq2hXLH0c9x5tzKM92g9/G+uR1udxVys6RU8QqCsAGo vxiXCFZwVRMChEYOb/WXWVOKv1/bnbE2rN0U8AirT2nxvf5UCEqyUpVI46AGs/dR GAot9jtfxX3tF1wM7E/lgAqBi54bv+Wrzy1ontwo0KHHQcgKo8H94scxE/8YFCxZ ICX4u65gjDLehjTNk0eGQ8GhcO/R7sachZvg7UJTsKTw8xk16t1vuMwSJ9rjKDx1 ZquopxFs8kIG+bfzZsY1YNnA =88FJ -----END PGP SIGNATURE----- --=-mx5cNm777Bf9oKHRXlOr--