Linux Serial subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Johan Hovold" <johan@kernel.org>
Cc: linux-serial@vger.kernel.org
Subject: Re: [PATCH] serial core: fix use-after-free after driver module unload
Date: Thu, 12 Nov 2026 10:28:23 +0000	[thread overview]
Message-ID: <sashiko-outbox-210941@kernel.org> (raw)
In-Reply-To: <20261112100541.348390-1-johan@kernel.org>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] serial: core: use-after-free and early module_put() in
  uart_cleanup()
- [Low] serial: core: inaccurate Fixes trailer in commit message
--

commit 6a2bc2d8089d9c95546b231a0390b02e8dc6cd97
Author: Johan Hovold <johan@kernel.org>

> serial core: fix use-after-free after driver module unload
>
> Deregistering a uart driver frees the driver uart state including the
> tty ports themselves.
>
> Take a reference to the uart driver module at install() so that the
> uart state and resources like the tty driver name do not go away while a
> tty is still open.
>
> This specifically avoids use-after-free when accessing the tty port and
> crashes when accessing the tty driver name (e.g. in the tty printk
> macros) when a tty is closed after its driver module has been unloaded.
>
> It also makes sure that the uart state is still valid when waking up any
> waiters after releasing the final uart port reference in
> uart_port_deref().
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Johan Hovold <johan@kernel.org>

[Severity: Low]
1da177e4c3f4 ("Linux-2.6.12-rc2") cannot be resolved in the git history,
and uart_register_driver() originally set normal->owner = drv->owner until
it was removed by 2f16669d322e ("TTY: remove re-assignments to tty_driver
members").  Should the Fixes tag reference that commit instead?

> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index b06d2649be343..2160e72780b45 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -1935,10 +1935,25 @@ static int uart_install(struct tty_driver *driver, struct tty_struct *tty)
>  {
>  	struct uart_driver *drv = driver->driver_state;
>  	struct uart_state *state = drv->state + tty->index;
> +	int ret;
> +
> +	if (!try_module_get(drv->owner))
> +		return -ENODEV;
>  
>  	tty->driver_data = state;
>  
> -	return tty_standard_install(driver, tty);
> +	ret = tty_standard_install(driver, tty);
> +	if (ret)
> +		module_put(drv->owner);
> +
> +	return ret;
> +}
> +
> +static void uart_cleanup(struct tty_struct *tty)
> +{
> +	struct uart_driver *drv = tty->driver->driver_state;
> +
> +	module_put(drv->owner);
>  }

[Severity: High]
Can uart_cleanup() dereference freed memory via tty->driver->driver_state
when a device is unbound while a TTY is open?

Drivers such as sccnxp and tegra-tcu embed struct uart_driver inside
devm-allocated device state and call uart_unregister_driver() from their
.remove() callback.  Holding a reference to drv->owner does not prevent a
sysfs unbind, which unregisters the driver and frees the struct containing
struct uart_driver while the TTY remains open:

CPU0                                  CPU1
sccnxp_remove()
  uart_unregister_driver(&s->uart)
devres_release_all()
  kfree(s)
                                      release_one_tty()
                                        uart_cleanup()
                                          drv = tty->driver->driver_state;
                                          module_put(drv->owner);  <-- use-after-free

In addition, release_one_tty() runs tty->ops->cleanup(tty) before
tty_driver_kref_put(driver):

drivers/tty/tty_io.c:release_one_tty() {
	struct tty_driver *driver = tty->driver;
	struct module *owner = driver->owner;

	if (tty->ops->cleanup)
		tty->ops->cleanup(tty);

	tty_driver_kref_put(driver);
	module_put(owner);
}

Dropping drv->owner in uart_cleanup() allows a concurrent rmmod to finish
uart_unregister_driver() and unmap the module before release_one_tty()
calls tty_driver_kref_put(driver) -> destruct_tty_driver(), leaving
/proc/tty/driver/<driver_name> registered while drv and drv->state are
already freed.  Leaving normal->owner unset also leaves cdev->owner unset,
so an open() racing with module unload is not blocked in chrdev_open() and
can call tty_driver_kref_put() in tty_open_by_driver() after the module has
been unloaded.

Setting normal->owner = drv->owner (or passing drv->owner to
__tty_alloc_driver()) in uart_register_driver() lets the TTY core manage
the module reference via struct tty_driver without dereferencing
tty->driver->driver_state in cleanup.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261112100541.348390-1-johan@kernel.org?part=1

      parent reply	other threads:[~2026-11-12 10:28 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-12 10:05 [PATCH] serial core: fix use-after-free after driver module unload Johan Hovold
2026-11-12 10:12 ` Johan Hovold
2026-11-12 10:28 ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-210941@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=johan@kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox