Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aee5da78 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

serdev: fix tty-port client deregistration



The port client data must be set when registering the serdev controller
or client deregistration will fail (and the serdev devices are left
registered and allocated) if the port was never opened in between.

Make sure to clear the port client data on any probe errors to avoid a
use-after-free when the client is later deregistered unconditionally
(e.g. in a tty-port deregistration helper).

Also move port client operation initialisation to registration. Note
that the client ops must be restored on failed probe.

Fixes: bed35c6d ("serdev: add a tty port controller driver")
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
Reviewed-by: default avatarRob Herring <robh@kernel.org>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d3ba126a
Loading
Loading
Loading
Loading
+10 −5
Original line number Original line Diff line number Diff line
@@ -102,9 +102,6 @@ static int ttyport_open(struct serdev_controller *ctrl)
		return PTR_ERR(tty);
		return PTR_ERR(tty);
	serport->tty = tty;
	serport->tty = tty;


	serport->port->client_ops = &client_ops;
	serport->port->client_data = ctrl;

	if (tty->ops->open)
	if (tty->ops->open)
		tty->ops->open(serport->tty, NULL);
		tty->ops->open(serport->tty, NULL);
	else
	else
@@ -215,6 +212,7 @@ struct device *serdev_tty_port_register(struct tty_port *port,
					struct device *parent,
					struct device *parent,
					struct tty_driver *drv, int idx)
					struct tty_driver *drv, int idx)
{
{
	const struct tty_port_client_operations *old_ops;
	struct serdev_controller *ctrl;
	struct serdev_controller *ctrl;
	struct serport *serport;
	struct serport *serport;
	int ret;
	int ret;
@@ -233,15 +231,22 @@ struct device *serdev_tty_port_register(struct tty_port *port,


	ctrl->ops = &ctrl_ops;
	ctrl->ops = &ctrl_ops;


	old_ops = port->client_ops;
	port->client_ops = &client_ops;
	port->client_data = ctrl;

	ret = serdev_controller_add(ctrl);
	ret = serdev_controller_add(ctrl);
	if (ret)
	if (ret)
		goto err_controller_put;
		goto err_reset_data;


	dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx);
	dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx);
	return &ctrl->dev;
	return &ctrl->dev;


err_controller_put:
err_reset_data:
	port->client_data = NULL;
	port->client_ops = old_ops;
	serdev_controller_put(ctrl);
	serdev_controller_put(ctrl);

	return ERR_PTR(ret);
	return ERR_PTR(ret);
}
}