* [PATCH v4] usb: gadget: u_serial: fix NULL deref in gs_close() after failed open
@ 2026-10-13 20:57 ` Brian Ellis via B4 Relay
0 siblings, 0 replies; 3+ messages in thread
From: Brian Ellis @ 2026-10-13 20:57 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, linux-kernel, Kuen-Han Tsai, Prashanth K,
Syed Tayyab Farooq, Krystian Kaniewski,
syzbot+782b2f1063e38ba8fa6e, stable, Brian Ellis
gs_close() opens with
struct gs_port *port = tty->driver_data;
...
spin_lock_irq(&port->port_lock);
and never checks port. gs_open() assigns tty->driver_data only on the
port.count 0 -> 1 edge, so any failure earlier in gs_open() leaves it NULL,
and tty_open() calls tty_release(), and hence ->close(), when ->open()
fails.
syzbot hit exactly this on arm64. Fault injection failed the kfifo_alloc()
of the write buffer in gs_open():
__kfifo_alloc_node+0x10c/0x208 lib/kfifo.c:44
gs_open+0x144/0x514 drivers/usb/gadget/function/u_serial.c:636
tty_open+0x404/0x89c drivers/tty/tty_io.c:2137
and the tty core's close of the failed open then took port_lock through
the NULL port:
BUG: unable to handle kernel paging request in gs_close
KASAN: null-ptr-deref in range [0x00000000000003a0-0x00000000000003a7]
Call trace:
spin_lock_irq include/linux/spinlock.h:372 [inline]
gs_close+0xac/0x65c drivers/usb/gadget/function/u_serial.c:698
tty_release+0x2c4/0xffc drivers/tty/tty_io.c:1745
tty_open+0x46c/0x89c drivers/tty/tty_io.c:2146
Return early instead. There is nothing to release when the open never got
far enough to claim the port.
Unlike the check reverted by commit f6c7bc4a6823 ("Revert "usb: gadget:
u_serial: Add null pointer check in gs_start_io""), this is not hiding a
race: the tty core calls ->close() for an ->open() that failed by design,
so driver_data is legitimately unset on that path.
Fixes: c1dca562be8a ("usb gadget: split out serial core")
Reported-by: syzbot+782b2f1063e38ba8fa6e@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=782b2f1063e38ba8fa6e
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Brian Ellis <brianellis@gotenna.com>
---
Found by reading the code while working on a downstream 6.6-based gadget
kernel, where gserial_free_line() clearing ports[n].port makes the same
path reachable, and matched to the syzbot report afterwards. It has not
been hit here, and syzbot has no reproducer for it.
Compile-tested against usb-linus with allmodconfig (CONFIG_USB_U_SERIAL=m).
Not boot-tested on mainline, and the failed-open path has not been
exercised.
Two lifetime reworks posted for a different syzbot report in this driver
(fe63e4d633540f230624) add the same check as part of larger changes:
https://lore.kernel.org/r/20260910105359.12915-1-syedtayyabfarooq08@gmail.com
https://lore.kernel.org/r/6941beb7-8cae-4cc5-ba07-e1c8a8753fe1@mail.kernel.org
This is the minimal fix, aimed at stable. If either of those lands first,
this one is redundant.
---
Changes in v4:
- Reported-by:/Closes: now use the ID from syzbot's public report; v3
used the ID from its moderation stage.
- Quote the trace from the public report, including the injected
kfifo_alloc() failure in gs_open(). v3 misread the shadow index 0x74 as
the offset (it is 0x3a0) and quoted a "Write" line not in the report.
- Correct v3's notes: syzbot has no reproducer, and this was found by
reading the code, not hit downstream.
- Mention the two overlapping lifetime reworks.
- Add Assisted-by: LLM.
- Link to v3: https://lore.kernel.org/r/20260928-u_serial-gs-close-null-v3-1-c688d93b4c49@gotenna.com
Changes in v3:
- Restore the Reported-by:/Closes: syzbot tags and the KASAN trace. They were
dropped from v1 and v2 in error when the commit message was rewritten. The
report is still open, and without Closes: syzbot cannot associate this fix
with it.
- Say why this differs from the check reverted in f6c7bc4a6823, since that
revert's reasoning is the obvious objection here.
- Link to v2: https://lore.kernel.org/r/20260927-u_serial-gs-close-null-v2-1-bdedf57fe96f@gotenna.com
Changes in v2:
- Remove the comment above the check, rather than reword it as Prashanth
suggested. The commit message already explains the path that leaves
tty->driver_data NULL, so the comment only restated it. Happy to add a
reworded one instead if that is preferred.
- Link to v1: https://lore.kernel.org/r/20260910-u_serial-gs-close-null-v1-1-9a5e848b1dfb@gotenna.com
---
drivers/usb/gadget/function/u_serial.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index cdd1dfc66..892d2673e 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -695,6 +695,9 @@ static void gs_close(struct tty_struct *tty, struct file *file)
struct gs_port *port = tty->driver_data;
struct gserial *gser;
+ if (!port)
+ return;
+
spin_lock_irq(&port->port_lock);
if (port->port.count != 1) {
---
base-commit: be4219dd98608736e13e0b790ef742b76a13254d
change-id: 20260910-u_serial-gs-close-null-a80a436666e8
Best regards,
--
Brian Ellis <brianellis@gotenna.com>
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v4] usb: gadget: u_serial: fix NULL deref in gs_close() after failed open
@ 2026-10-13 20:57 ` Brian Ellis via B4 Relay
0 siblings, 0 replies; 3+ messages in thread
From: Brian Ellis via B4 Relay @ 2026-10-13 20:57 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, linux-kernel, Kuen-Han Tsai, Prashanth K,
Syed Tayyab Farooq, Krystian Kaniewski,
syzbot+782b2f1063e38ba8fa6e, stable, Brian Ellis
From: Brian Ellis <brianellis@gotenna.com>
gs_close() opens with
struct gs_port *port = tty->driver_data;
...
spin_lock_irq(&port->port_lock);
and never checks port. gs_open() assigns tty->driver_data only on the
port.count 0 -> 1 edge, so any failure earlier in gs_open() leaves it NULL,
and tty_open() calls tty_release(), and hence ->close(), when ->open()
fails.
syzbot hit exactly this on arm64. Fault injection failed the kfifo_alloc()
of the write buffer in gs_open():
__kfifo_alloc_node+0x10c/0x208 lib/kfifo.c:44
gs_open+0x144/0x514 drivers/usb/gadget/function/u_serial.c:636
tty_open+0x404/0x89c drivers/tty/tty_io.c:2137
and the tty core's close of the failed open then took port_lock through
the NULL port:
BUG: unable to handle kernel paging request in gs_close
KASAN: null-ptr-deref in range [0x00000000000003a0-0x00000000000003a7]
Call trace:
spin_lock_irq include/linux/spinlock.h:372 [inline]
gs_close+0xac/0x65c drivers/usb/gadget/function/u_serial.c:698
tty_release+0x2c4/0xffc drivers/tty/tty_io.c:1745
tty_open+0x46c/0x89c drivers/tty/tty_io.c:2146
Return early instead. There is nothing to release when the open never got
far enough to claim the port.
Unlike the check reverted by commit f6c7bc4a6823 ("Revert "usb: gadget:
u_serial: Add null pointer check in gs_start_io""), this is not hiding a
race: the tty core calls ->close() for an ->open() that failed by design,
so driver_data is legitimately unset on that path.
Fixes: c1dca562be8a ("usb gadget: split out serial core")
Reported-by: syzbot+782b2f1063e38ba8fa6e@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=782b2f1063e38ba8fa6e
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Brian Ellis <brianellis@gotenna.com>
---
Found by reading the code while working on a downstream 6.6-based gadget
kernel, where gserial_free_line() clearing ports[n].port makes the same
path reachable, and matched to the syzbot report afterwards. It has not
been hit here, and syzbot has no reproducer for it.
Compile-tested against usb-linus with allmodconfig (CONFIG_USB_U_SERIAL=m).
Not boot-tested on mainline, and the failed-open path has not been
exercised.
Two lifetime reworks posted for a different syzbot report in this driver
(fe63e4d633540f230624) add the same check as part of larger changes:
https://lore.kernel.org/r/20260910105359.12915-1-syedtayyabfarooq08@gmail.com
https://lore.kernel.org/r/6941beb7-8cae-4cc5-ba07-e1c8a8753fe1@mail.kernel.org
This is the minimal fix, aimed at stable. If either of those lands first,
this one is redundant.
---
Changes in v4:
- Reported-by:/Closes: now use the ID from syzbot's public report; v3
used the ID from its moderation stage.
- Quote the trace from the public report, including the injected
kfifo_alloc() failure in gs_open(). v3 misread the shadow index 0x74 as
the offset (it is 0x3a0) and quoted a "Write" line not in the report.
- Correct v3's notes: syzbot has no reproducer, and this was found by
reading the code, not hit downstream.
- Mention the two overlapping lifetime reworks.
- Add Assisted-by: LLM.
- Link to v3: https://lore.kernel.org/r/20260928-u_serial-gs-close-null-v3-1-c688d93b4c49@gotenna.com
Changes in v3:
- Restore the Reported-by:/Closes: syzbot tags and the KASAN trace. They were
dropped from v1 and v2 in error when the commit message was rewritten. The
report is still open, and without Closes: syzbot cannot associate this fix
with it.
- Say why this differs from the check reverted in f6c7bc4a6823, since that
revert's reasoning is the obvious objection here.
- Link to v2: https://lore.kernel.org/r/20260927-u_serial-gs-close-null-v2-1-bdedf57fe96f@gotenna.com
Changes in v2:
- Remove the comment above the check, rather than reword it as Prashanth
suggested. The commit message already explains the path that leaves
tty->driver_data NULL, so the comment only restated it. Happy to add a
reworded one instead if that is preferred.
- Link to v1: https://lore.kernel.org/r/20260910-u_serial-gs-close-null-v1-1-9a5e848b1dfb@gotenna.com
---
drivers/usb/gadget/function/u_serial.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index cdd1dfc66..892d2673e 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -695,6 +695,9 @@ static void gs_close(struct tty_struct *tty, struct file *file)
struct gs_port *port = tty->driver_data;
struct gserial *gser;
+ if (!port)
+ return;
+
spin_lock_irq(&port->port_lock);
if (port->port.count != 1) {
---
base-commit: be4219dd98608736e13e0b790ef742b76a13254d
change-id: 20260910-u_serial-gs-close-null-a80a436666e8
Best regards,
--
Brian Ellis <brianellis@gotenna.com>
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v4] usb: gadget: u_serial: fix NULL deref in gs_close() after failed open
2026-10-13 20:57 ` Brian Ellis via B4 Relay
(?)
@ 2026-10-13 21:06 ` sashiko-bot
-1 siblings, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-10-13 21:06 UTC (permalink / raw)
To: Brian Ellis; +Cc: linux-usb
> From: Brian Ellis <brianellis@gotenna.com>
>
> gs_close() opens with
>
> struct gs_port *port = tty->driver_data;
> ...
> spin_lock_irq(&port->port_lock);
>
> and never checks port. gs_open() assigns tty->driver_data only on the
> port.count 0 -> 1 edge, so any failure earlier in gs_open() leaves it NULL,
> and tty_open() calls tty_release(), and hence ->close(), when ->open()
> fails.
>
> syzbot hit exactly this on arm64. Fault injection failed the kfifo_alloc()
> of the write buffer in gs_open():
> [ ... ]
> Reported-by: syzbot+782b2f1063e38ba8fa6e@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=782b2f1063e38ba8fa6e
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Brian Ellis <brianellis@gotenna.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261013-u_serial-gs-close-null-v4-1-9ea038501994@gotenna.com?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-13 21:06 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 20:57 [PATCH v4] usb: gadget: u_serial: fix NULL deref in gs_close() after failed open Brian Ellis
2026-10-13 20:57 ` Brian Ellis via B4 Relay
2026-10-13 21:06 ` sashiko-bot
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.