Skip to content

Commit 0c5aae5

Browse files
jhovoldgregkh
authored andcommitted
serdev: ttyport: restore client ops on deregistration
The serdev tty-port controller driver should reset the tty-port client operations also on deregistration to avoid a NULL-pointer dereference in case the port is later re-registered as a normal tty device. Note that this can only happen with tty drivers such as 8250 which have statically allocated port structures that can end up being reused and where a later registration would not register a serdev controller (e.g. due to registration errors or if the devicetree has been changed in between). Specifically, this can be an issue for any statically defined ports that would be registered by 8250 core when an 8250 driver is being unbound. Fixes: bed35c6 ("serdev: add a tty port controller driver") Cc: stable <[email protected]> # 4.11 Reported-by: Loic Poulain <[email protected]> Signed-off-by: Johan Hovold <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 87c5cbf commit 0c5aae5

File tree

3 files changed

+7
-6
lines changed

3 files changed

+7
-6
lines changed

drivers/tty/serdev/serdev-ttyport.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ struct device *serdev_tty_port_register(struct tty_port *port,
265265
struct device *parent,
266266
struct tty_driver *drv, int idx)
267267
{
268-
const struct tty_port_client_operations *old_ops;
269268
struct serdev_controller *ctrl;
270269
struct serport *serport;
271270
int ret;
@@ -284,7 +283,6 @@ struct device *serdev_tty_port_register(struct tty_port *port,
284283

285284
ctrl->ops = &ctrl_ops;
286285

287-
old_ops = port->client_ops;
288286
port->client_ops = &client_ops;
289287
port->client_data = ctrl;
290288

@@ -297,7 +295,7 @@ struct device *serdev_tty_port_register(struct tty_port *port,
297295

298296
err_reset_data:
299297
port->client_data = NULL;
300-
port->client_ops = old_ops;
298+
port->client_ops = &tty_port_default_client_ops;
301299
serdev_controller_put(ctrl);
302300

303301
return ERR_PTR(ret);
@@ -312,8 +310,8 @@ int serdev_tty_port_unregister(struct tty_port *port)
312310
return -ENODEV;
313311

314312
serdev_controller_remove(ctrl);
315-
port->client_ops = NULL;
316313
port->client_data = NULL;
314+
port->client_ops = &tty_port_default_client_ops;
317315
serdev_controller_put(ctrl);
318316

319317
return 0;

drivers/tty/tty_port.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ static void tty_port_default_wakeup(struct tty_port *port)
5252
}
5353
}
5454

55-
static const struct tty_port_client_operations default_client_ops = {
55+
const struct tty_port_client_operations tty_port_default_client_ops = {
5656
.receive_buf = tty_port_default_receive_buf,
5757
.write_wakeup = tty_port_default_wakeup,
5858
};
59+
EXPORT_SYMBOL_GPL(tty_port_default_client_ops);
5960

6061
void tty_port_init(struct tty_port *port)
6162
{
@@ -68,7 +69,7 @@ void tty_port_init(struct tty_port *port)
6869
spin_lock_init(&port->lock);
6970
port->close_delay = (50 * HZ) / 100;
7071
port->closing_wait = (3000 * HZ) / 100;
71-
port->client_ops = &default_client_ops;
72+
port->client_ops = &tty_port_default_client_ops;
7273
kref_init(&port->kref);
7374
}
7475
EXPORT_SYMBOL(tty_port_init);

include/linux/tty.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ struct tty_port_client_operations {
225225
void (*write_wakeup)(struct tty_port *port);
226226
};
227227

228+
extern const struct tty_port_client_operations tty_port_default_client_ops;
229+
228230
struct tty_port {
229231
struct tty_bufhead buf; /* Locked internally */
230232
struct tty_struct *tty; /* Back pointer */

0 commit comments

Comments
 (0)