[PATCH RFC] USB: serial: spcp8x5: drop carrier_raised callback
"syzbot" <[email protected]>
| Newsgroups | dev.linux.lists.syzbot |
|---|---|
| Message-ID | <[email protected]> |
When a TTY device is opened, the generic TTY layer calls
tty_port_block_til_ready() to wait for the carrier detect (DCD) line to be
raised. This function sets the task state to TASK_INTERRUPTIBLE and then
calls the driver's .carrier_raised callback.
In the spcp8x5 driver, the spcp8x5_carrier_raised() callback calls
spcp8x5_get_msr(), which allocates memory with GFP_KERNEL and sends a USB
control message. Both of these operations can sleep. Calling sleeping
functions while the task state is TASK_INTERRUPTIBLE is invalid and
triggers a __might_sleep warning:
do not call blocking ops when !TASK_RUNNING; state=1 set at
[<ffffffff819e7a64>] prepare_to_wait+0x174/0x210 kernel/sched/wait.c:256
WARNING: kernel/sched/core.c:9124 at __might_sleep+0x92/0xf0
kernel/sched/core.c:9120
...
Call Trace:
<TASK>
might_alloc include/linux/sched/mm.h:323 [inline]
slab_pre_alloc_hook mm/slub.c:4537 [inline]
slab_alloc_node mm/slub.c:4897 [inline]
__kmalloc_cache_noprof+0x94/0x660 mm/slub.c:5485
_kmalloc_noprof include/linux/slab.h:988 [inline]
_kzalloc_noprof include/linux/slab.h:1309 [inline]
spcp8x5_get_msr+0xd3/0x2d0 drivers/usb/serial/spcp8x5.c:197
spcp8x5_carrier_raised+0x30/0x80 drivers/usb/serial/spcp8x5.c:243
serial_port_carrier_raised+0x8c/0xc0 drivers/usb/serial/usb-serial.c:757
tty_port_carrier_raised drivers/tty/tty_port.c:441 [inline]
tty_port_block_til_ready+0x449/0x8b0 drivers/tty/tty_port.c:559
tty_open+0x48a/0xcc0 drivers/tty/tty_io.c:2137
Furthermore, because usb_control_msg() waits for the URB completion, it
internally uses wait_for_completion_timeout(), which resets the task state
back to TASK_RUNNING. When spcp8x5_carrier_raised() returns to
tty_port_block_til_ready(), the task state is no longer TASK_INTERRUPTIBLE.
The subsequent schedule() call sees TASK_RUNNING and returns immediately
without blocking, accidentally turning the wait loop into a 100% CPU
busy-polling loop that constantly spams the USB device with control
messages until the carrier is raised.
Unlike some other USB serial adapters, the spcp8x5 hardware does not have
an interrupt IN endpoint. This means it cannot receive asynchronous
notifications when the modem status changes, and therefore the driver can
never wake up a sleeping task waiting for carrier detect. A device that
cannot asynchronously detect carrier changes cannot support blocking on
carrier detect.
Fix this by completely removing the .carrier_raised callback from the
spcp8x5_device struct and deleting the spcp8x5_carrier_raised() function.
When .carrier_raised is NULL, tty_port_carrier_raised() defaults to
returning true. This allows the TTY open operation to proceed immediately
without blocking, which is the standard and expected behavior for devices
lacking asynchronous carrier detect capabilities.
Fixes: e1ed212d8593 ("USB: spcp8x5: add proper modem-status support")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=3b514b87202742f22c44
Link: https://syzkaller.appspot.com/ai_job?id=0fb9718c-010d-42ad-a2c2-a1593fbfbe39
To: "Greg Kroah-Hartman" <[email protected]>
To: "Johan Hovold" <[email protected]>
To: <[email protected]>
To: "Johan Hovold" <[email protected]>
Cc: <[email protected]>
---
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index c11d64bf0..f610aef6b 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -235,18 +235,6 @@ static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value,
dev_err(&port->dev, "failed to set work mode: %d\n", ret);
}
-static int spcp8x5_carrier_raised(struct usb_serial_port *port)
-{
- u8 msr;
- int ret;
-
- ret = spcp8x5_get_msr(port, &msr);
- if (ret || msr & MSR_STATUS_LINE_DCD)
- return 1;
-
- return 0;
-}
-
static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
{
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
@@ -458,7 +446,6 @@ static struct usb_serial_driver spcp8x5_device = {
.num_bulk_out = 1,
.open = spcp8x5_open,
.dtr_rts = spcp8x5_dtr_rts,
- .carrier_raised = spcp8x5_carrier_raised,
.set_termios = spcp8x5_set_termios,
.init_termios = spcp8x5_init_termios,
.tiocmget = spcp8x5_tiocmget,
base-commit: 075b74841bd0065a3bda3440873c747938e69b68
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).
See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
The person who has signed off on the patch is responsible for
addressing comments.
syzbot engineers can be reached at [email protected].