* FAILED: patch "[PATCH] tty: tty_port: restore TTY_IO_ERROR on activation failure" failed to apply to 6.12-stable tree
@ 2026-10-05 8:50 gregkh
2026-10-05 17:17 ` [PATCH 6.12.y 1/3] tty: introduce tty_port_tty guard() Sasha Levin
0 siblings, 1 reply; 4+ messages in thread
From: gregkh @ 2026-10-05 8:50 UTC (permalink / raw)
To: johan, gregkh, stable; +Cc: stable
The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 56964f6a31238fb41d5830bb42520c5b10ff7d8f
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026100521-mammal-arose-32f1@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 56964f6a31238fb41d5830bb42520c5b10ff7d8f Mon Sep 17 00:00:00 2001
From: Johan Hovold <johan@kernel.org>
Date: Tue, 8 Sep 2026 10:40:00 +0200
Subject: [PATCH] tty: tty_port: restore TTY_IO_ERROR on activation failure
Make sure to restore the TTY_IO_ERROR flag if activation fails to
prevent I/O attempts on a port that is gone or powered down.
This specifically avoids issues like kernel panic due to unclocked
accesses or NULL-pointer dereferences when accessing powered down or
deregistered ports when a TTY ioctl races with hangup and open.
Note that the flag is set again in tty_port_close() but not restoring it
on activation failure leaves a window where drivers fail to handle the
ioctl-hangup race.
Fixes: a9a37ec33a1b ("tty: tty_port: Move the IO_ERROR clear")
Cc: stable <stable@kernel.org> # 2.6.33
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20260908084000.218528-1-johan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 54359310e293..ae33987207b6 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -767,8 +767,10 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
- if (retval)
+ if (retval) {
+ set_bit(TTY_IO_ERROR, &tty->flags);
return retval;
+ }
}
tty_port_set_initialized(port, true);
}
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 6.12.y 1/3] tty: introduce tty_port_tty guard()
2026-10-05 8:50 FAILED: patch "[PATCH] tty: tty_port: restore TTY_IO_ERROR on activation failure" failed to apply to 6.12-stable tree gregkh
@ 2026-10-05 17:17 ` Sasha Levin
2026-10-05 17:17 ` [PATCH 6.12.y 2/3] tty: tty_port: use guard()s Sasha Levin
2026-10-05 17:17 ` [PATCH 6.12.y 3/3] tty: tty_port: restore TTY_IO_ERROR on activation failure Sasha Levin
0 siblings, 2 replies; 4+ messages in thread
From: Sasha Levin @ 2026-10-05 17:17 UTC (permalink / raw)
To: stable; +Cc: Jiri Slaby (SUSE), Greg Kroah-Hartman, Sasha Levin
From: "Jiri Slaby (SUSE)" <jirislaby@kernel.org>
[ Upstream commit e8398b8aed50382c21fcec77e80a5314e7c45c25 ]
Having this, guards like these work:
scoped_guard(tty_port_tty, port)
tty_wakeup(scoped_tty());
See e.g. "tty_port: use scoped_guard()" later in this series.
The definitions depend on CONFIG_TTY. It's due to tty_kref_put().
On !CONFIG_TTY, it is an inline and its declaration would conflict. The
guards are not needed in that case, of course.
Signed-off-by: "Jiri Slaby (SUSE)" <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20250814072456.182853-3-jirislaby@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 56964f6a3123 ("tty: tty_port: restore TTY_IO_ERROR on activation failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/tty_port.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h
index 41b1c72745ca5..5e2cd738aceaf 100644
--- a/include/linux/tty_port.h
+++ b/include/linux/tty_port.h
@@ -273,4 +273,18 @@ static inline void tty_port_tty_vhangup(struct tty_port *port)
__tty_port_tty_hangup(port, false, false);
}
+#ifdef CONFIG_TTY
+void tty_kref_put(struct tty_struct *tty);
+__DEFINE_CLASS_IS_CONDITIONAL(tty_port_tty, true);
+__DEFINE_UNLOCK_GUARD(tty_port_tty, struct tty_struct, tty_kref_put(_T->lock));
+static inline class_tty_port_tty_t class_tty_port_tty_constructor(struct tty_port *tport)
+{
+ class_tty_port_tty_t _t = {
+ .lock = tty_port_tty_get(tport),
+ };
+ return _t;
+}
+#define scoped_tty() ((struct tty_struct *)(__guard_ptr(tty_port_tty)(&scope)))
+#endif
+
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 6.12.y 2/3] tty: tty_port: use guard()s
2026-10-05 17:17 ` [PATCH 6.12.y 1/3] tty: introduce tty_port_tty guard() Sasha Levin
@ 2026-10-05 17:17 ` Sasha Levin
2026-10-05 17:17 ` [PATCH 6.12.y 3/3] tty: tty_port: restore TTY_IO_ERROR on activation failure Sasha Levin
1 sibling, 0 replies; 4+ messages in thread
From: Sasha Levin @ 2026-10-05 17:17 UTC (permalink / raw)
To: stable; +Cc: Jiri Slaby (SUSE), Greg Kroah-Hartman, Sasha Levin
From: "Jiri Slaby (SUSE)" <jirislaby@kernel.org>
[ Upstream commit 88d65e22c8bf7a4b6d61098d67727d14f1c5930f ]
Having all the new guards, use them in the tty_port code. This improves
readability, makes error handling easier, and marks locked portions of
code explicit.
Signed-off-by: "Jiri Slaby (SUSE)" <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20250814072456.182853-6-jirislaby@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 56964f6a3123 ("tty: tty_port: restore TTY_IO_ERROR on activation failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/tty_port.c | 168 ++++++++++++++++++-----------------------
1 file changed, 74 insertions(+), 94 deletions(-)
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index e10ccce1653e3..64b2584ff7a18 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -63,12 +63,8 @@ static void tty_port_default_lookahead_buf(struct tty_port *port, const u8 *p,
static void tty_port_default_wakeup(struct tty_port *port)
{
- struct tty_struct *tty = tty_port_tty_get(port);
-
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ scoped_guard(tty_port_tty, port)
+ tty_wakeup(scoped_tty());
}
const struct tty_port_client_operations tty_port_default_client_ops = {
@@ -245,26 +241,27 @@ EXPORT_SYMBOL_GPL(tty_port_unregister_device);
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
/* We may sleep in get_zeroed_page() */
- mutex_lock(&port->buf_mutex);
- if (port->xmit_buf == NULL) {
- port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
- if (port->xmit_buf)
- kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
- }
- mutex_unlock(&port->buf_mutex);
+ guard(mutex)(&port->buf_mutex);
+
+ if (port->xmit_buf)
+ return 0;
+
+ port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
if (port->xmit_buf == NULL)
return -ENOMEM;
+
+ kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
+
return 0;
}
EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
void tty_port_free_xmit_buf(struct tty_port *port)
{
- mutex_lock(&port->buf_mutex);
+ guard(mutex)(&port->buf_mutex);
free_page((unsigned long)port->xmit_buf);
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- mutex_unlock(&port->buf_mutex);
}
EXPORT_SYMBOL(tty_port_free_xmit_buf);
@@ -321,13 +318,8 @@ EXPORT_SYMBOL(tty_port_put);
*/
struct tty_struct *tty_port_tty_get(struct tty_port *port)
{
- unsigned long flags;
- struct tty_struct *tty;
-
- spin_lock_irqsave(&port->lock, flags);
- tty = tty_kref_get(port->tty);
- spin_unlock_irqrestore(&port->lock, flags);
- return tty;
+ guard(spinlock_irqsave)(&port->lock);
+ return tty_kref_get(port->tty);
}
EXPORT_SYMBOL(tty_port_tty_get);
@@ -341,12 +333,9 @@ EXPORT_SYMBOL(tty_port_tty_get);
*/
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
{
- unsigned long flags;
-
- spin_lock_irqsave(&port->lock, flags);
+ guard(spinlock_irqsave)(&port->lock);
tty_kref_put(port->tty);
port->tty = tty_kref_get(tty);
- spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_tty_set);
@@ -362,24 +351,24 @@ EXPORT_SYMBOL(tty_port_tty_set);
*/
static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
{
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
+
if (port->console)
- goto out;
+ return;
- if (tty_port_initialized(port)) {
- tty_port_set_initialized(port, false);
- /*
- * Drop DTR/RTS if HUPCL is set. This causes any attached
- * modem to hang up the line.
- */
- if (tty && C_HUPCL(tty))
- tty_port_lower_dtr_rts(port);
+ if (!tty_port_initialized(port))
+ return;
- if (port->ops->shutdown)
- port->ops->shutdown(port);
- }
-out:
- mutex_unlock(&port->mutex);
+ tty_port_set_initialized(port, false);
+ /*
+ * Drop DTR/RTS if HUPCL is set. This causes any attached
+ * modem to hang up the line.
+ */
+ if (tty && C_HUPCL(tty))
+ tty_port_lower_dtr_rts(port);
+
+ if (port->ops->shutdown)
+ port->ops->shutdown(port);
}
/**
@@ -394,15 +383,15 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
void tty_port_hangup(struct tty_port *port)
{
struct tty_struct *tty;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- port->count = 0;
- tty = port->tty;
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
- port->tty = NULL;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ port->count = 0;
+ tty = port->tty;
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
+ port->tty = NULL;
+ }
+
tty_port_set_active(port, false);
tty_port_shutdown(port, tty);
tty_kref_put(tty);
@@ -413,15 +402,16 @@ EXPORT_SYMBOL(tty_port_hangup);
void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async)
{
- struct tty_struct *tty = tty_port_tty_get(port);
+ scoped_guard(tty_port_tty, port) {
+ struct tty_struct *tty = scoped_tty();
- if (tty && (!check_clocal || !C_CLOCAL(tty))) {
- if (async)
- tty_hangup(tty);
- else
- tty_vhangup(tty);
+ if (!check_clocal || !C_CLOCAL(tty)) {
+ if (async)
+ tty_hangup(tty);
+ else
+ tty_vhangup(tty);
+ }
}
- tty_kref_put(tty);
}
EXPORT_SYMBOL_GPL(__tty_port_tty_hangup);
@@ -510,7 +500,6 @@ int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
int do_clocal = 0, retval;
- unsigned long flags;
DEFINE_WAIT(wait);
/* if non-blocking mode is set we can pass directly to open unless
@@ -539,10 +528,10 @@ int tty_port_block_til_ready(struct tty_port *port,
retval = 0;
/* The port lock protects the port counts */
- spin_lock_irqsave(&port->lock, flags);
- port->count--;
- port->blocked_open++;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ port->count--;
+ port->blocked_open++;
+ }
while (1) {
/* Indicate we are open */
@@ -581,11 +570,11 @@ int tty_port_block_til_ready(struct tty_port *port,
/* Update counts. A parallel hangup will have set count to zero and
* we must not mess that up further.
*/
- spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ }
if (retval == 0)
tty_port_set_active(port, true);
return retval;
@@ -624,28 +613,24 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
- unsigned long flags;
-
if (tty_hung_up_p(filp))
return 0;
- spin_lock_irqsave(&port->lock, flags);
- if (tty->count == 1 && port->count != 1) {
- tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
- port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- tty_warn(tty, "%s: bad port count (%d)\n", __func__,
- port->count);
- port->count = 0;
- }
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ if (tty->count == 1 && port->count != 1) {
+ tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
+ port->count);
+ port->count = 1;
+ }
+ if (--port->count < 0) {
+ tty_warn(tty, "%s: bad port count (%d)\n", __func__,
+ port->count);
+ port->count = 0;
+ }
- if (port->count) {
- spin_unlock_irqrestore(&port->lock, flags);
- return 0;
+ if (port->count)
+ return 0;
}
- spin_unlock_irqrestore(&port->lock, flags);
tty->closing = 1;
@@ -764,9 +749,8 @@ EXPORT_SYMBOL_GPL(tty_port_install);
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
- spin_lock_irq(&port->lock);
- ++port->count;
- spin_unlock_irq(&port->lock);
+ scoped_guard(spinlock_irq, &port->lock)
+ ++port->count;
tty_port_tty_set(port, tty);
/*
@@ -775,21 +759,17 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
* port mutex.
*/
- mutex_lock(&port->mutex);
-
- if (!tty_port_initialized(port)) {
+ scoped_guard(mutex, &port->mutex) {
+ if (tty_port_initialized(port))
+ break;
clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
-
- if (retval) {
- mutex_unlock(&port->mutex);
+ if (retval)
return retval;
- }
}
tty_port_set_initialized(port, true);
}
- mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);
}
EXPORT_SYMBOL(tty_port_open);
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 6.12.y 3/3] tty: tty_port: restore TTY_IO_ERROR on activation failure
2026-10-05 17:17 ` [PATCH 6.12.y 1/3] tty: introduce tty_port_tty guard() Sasha Levin
2026-10-05 17:17 ` [PATCH 6.12.y 2/3] tty: tty_port: use guard()s Sasha Levin
@ 2026-10-05 17:17 ` Sasha Levin
1 sibling, 0 replies; 4+ messages in thread
From: Sasha Levin @ 2026-10-05 17:17 UTC (permalink / raw)
To: stable; +Cc: Johan Hovold, stable, Greg Kroah-Hartman, Sasha Levin
From: Johan Hovold <johan@kernel.org>
[ Upstream commit 56964f6a31238fb41d5830bb42520c5b10ff7d8f ]
Make sure to restore the TTY_IO_ERROR flag if activation fails to
prevent I/O attempts on a port that is gone or powered down.
This specifically avoids issues like kernel panic due to unclocked
accesses or NULL-pointer dereferences when accessing powered down or
deregistered ports when a TTY ioctl races with hangup and open.
Note that the flag is set again in tty_port_close() but not restoring it
on activation failure leaves a window where drivers fail to handle the
ioctl-hangup race.
Fixes: a9a37ec33a1b ("tty: tty_port: Move the IO_ERROR clear")
Cc: stable <stable@kernel.org> # 2.6.33
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20260908084000.218528-1-johan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/tty_port.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 64b2584ff7a18..10d707e3c0344 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -765,8 +765,10 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
- if (retval)
+ if (retval) {
+ set_bit(TTY_IO_ERROR, &tty->flags);
return retval;
+ }
}
tty_port_set_initialized(port, true);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-05 17:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-05 8:50 FAILED: patch "[PATCH] tty: tty_port: restore TTY_IO_ERROR on activation failure" failed to apply to 6.12-stable tree gregkh
2026-10-05 17:17 ` [PATCH 6.12.y 1/3] tty: introduce tty_port_tty guard() Sasha Levin
2026-10-05 17:17 ` [PATCH 6.12.y 2/3] tty: tty_port: use guard()s Sasha Levin
2026-10-05 17:17 ` [PATCH 6.12.y 3/3] tty: tty_port: restore TTY_IO_ERROR on activation failure Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox