From: Greg KH <gregkh@linuxfoundation.org>
To: Gaosheng Cui <cuigaosheng1@huawei.com>
Cc: lujialin4@huawei.com, jirislaby@kernel.org,
hvilleneuve@dimonoff.com, kmehltretter@gmail.com,
john.ogness@linutronix.de, andriy.shevchenko@linux.intel.com,
tony@atomide.com, linux-serial@vger.kernel.org
Subject: Re: [PATCH -next] serial: core: fix NULL/dangling port_dev on failed re-register
Date: Wed, 23 Sep 2026 14:52:20 +0200 [thread overview]
Message-ID: <2026092332-divisible-hypocrite-d223@gregkh> (raw)
In-Reply-To: <20260914135154.3260303-1-cuigaosheng1@huawei.com>
On Mon, Sep 14, 2026 at 09:51:54PM +0800, Gaosheng Cui wrote:
> From: Cui GaoSheng <cuigaosheng1@huawei.com>
>
> serial8250_unregister_port() removes a port and then re-registers it
> against the legacy serial8250 device when that device is still
> present, ignoring the return value of uart_add_one_port(). When the
> re-register fails, the error path of serial_core_register_port()
> removes the port device but leaves port->port_dev dangling. A port
> that was never successfully registered (e.g. serial_core_port_device_add()
> failed) also reaches the unregister path with port->port_dev unset.
> serial8250 matches ports on ->dev, so such half-registered slots
> still reach serial_core_unregister_port() on the next unbind:
>
> Oops: general protection fault ... SMP KASAN PTI
> KASAN: null-ptr-deref in range [0x40-0x47]
> RIP: serial_core_unregister_port+0xe5/0xa00
> serial8250_unregister_port+0x103
> serial8250_remove+0x61
> device_release_driver_internal+0x38c
> unbind_store+0xd1
> kernfs_fop_write_iter+0x329
> vfs_write+0x5d0
> ksys_write+0xf7
> do_syscall_64+0xdd
> entry_SYSCALL_64_after_hwframe+0x77
>
> Fix the error path to clear port->port_dev and restore the state slot
> (guarded by line range) to the "not registered" state, and bail out of
> serial_core_unregister_port() when port_dev is NULL (either dangling
> from a failed re-register or never set).
>
> Fixes: 84a9582fd203 ("serial: core: Start managing serial controllers to enable runtime PM")
> Signed-off-by: Cui GaoSheng <cuigaosheng1@huawei.com>
> ---
Did you forget the Assited-by: tag?
> drivers/tty/serial/serial_core.c | 25 ++++++++++++++++++++++++-
> 1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 95774b0f1484..62d93c5964e2 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -3358,6 +3358,17 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
>
> err_unregister_port_dev:
> serial_base_port_device_remove(port->port_dev);
> + /*
> + * serial_base_port_device_remove() dropped the last reference to the
> + * port device, so leave no dangling ->port_dev behind. Restore the
> + * state slot to the same "not registered" state that
> + * serial_core_remove_one_port() produces on the normal path; the
> + * line range guard also covers the -EINVAL exit of
> + * serial_core_add_one_port() where line >= drv->nr.
> + */
> + port->port_dev = NULL;
> + if (port->line < drv->nr && drv->state[port->line].uart_port == port)
> + drv->state[port->line].uart_port = NULL;
How was this tested?
>
> err_unregister_ctrl_dev:
> serial_base_ctrl_device_remove(new_ctrl_dev);
> @@ -3373,11 +3384,23 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port
> {
> struct device *phys_dev = port->dev;
> struct serial_port_device *port_dev = port->port_dev;
> - struct serial_ctrl_device *ctrl_dev = serial_core_get_ctrl_dev(port_dev);
> + struct serial_ctrl_device *ctrl_dev;
> int ctrl_id = port->ctrl_id;
>
> + /*
> + * A port may be unregistered even though it was never successfully
> + * registered (e.g. an allocation failure aborted serial_core_register_port()
> + * part-way). Drivers like serial8250 remove ports matching on ->dev, so
> + * those half-registered ports still reach us with port_dev == NULL. Do not
> + * dereference it.
> + */
> + if (!port_dev)
> + return;
What keeps port_dev from not changing right after you read it?
thanks,
greg k-h
next prev parent reply other threads:[~2026-09-23 12:52 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-14 13:51 [PATCH -next] serial: core: fix NULL/dangling port_dev on failed re-register Gaosheng Cui
2026-09-14 14:23 ` sashiko-bot
2026-09-23 12:52 ` Greg KH [this message]
2026-09-24 13:28 ` cuigaosheng
2026-09-24 14:37 ` Greg KH
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=2026092332-divisible-hypocrite-d223@gregkh \
--to=gregkh@linuxfoundation.org \
--cc=andriy.shevchenko@linux.intel.com \
--cc=cuigaosheng1@huawei.com \
--cc=hvilleneuve@dimonoff.com \
--cc=jirislaby@kernel.org \
--cc=john.ogness@linutronix.de \
--cc=kmehltretter@gmail.com \
--cc=linux-serial@vger.kernel.org \
--cc=lujialin4@huawei.com \
--cc=tony@atomide.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.