Re: [BUG] usb: mdc800: possible circular locking dependency between io_lock and minor_rwsem

From: Oliver Neukum

Date: Wed Sep 16 2026 - 15:30:38 EST




On 14.09.26 09:36, CJ wrote:

Hi,


I am reporting a lockdep-detected circular locking dependency in the mdc800 USB
driver, triggered by a syzkaller USB reproducer. The issue is reproducible with
HEAD commit cee9395acd8043be0644b25c34bfa86623f2b935 (v7.3-rc1, Linux
7.3.0-rc1).


The reproducer connects a synthetic USB device through dummy_hcd that enumerates
as the mdc800 camera, then opens the character device node. No filesystem or
image input is involved; the trigger is the connect-then-open sequence on a
device that binds to this driver.

Hi,

please try the attached patch.

Regards
Oliver
From 01e4a5b7f215b5f69ec1fdde829c1cd09498a22f Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oneukum@xxxxxxxx>
Date: Wed, 16 Sep 2026 17:37:25 +0200
Subject: [PATCH] usb: misc: mdc800: avoid circular locking

No need for locking in probe()

Signed-off-by: Oliver Neukum <oneukum@xxxxxxxx>
---
drivers/usb/image/mdc800.c | 26 +++++++++-----------------
1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index f7caa1c5cbb7..9edf0afe8dad 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -480,15 +480,6 @@ static int mdc800_usb_probe (struct usb_interface *intf,

dev_info(&intf->dev, "Found Mustek MDC800 on USB.\n");

- mutex_lock(&mdc800->io_lock);
-
- retval = usb_register_dev(intf, &mdc800_class);
- if (retval) {
- dev_err(&intf->dev, "Not able to get a minor for this device.\n");
- mutex_unlock(&mdc800->io_lock);
- return -ENODEV;
- }
-
mdc800->dev=dev;
mdc800->open=0;

@@ -526,7 +517,11 @@ static int mdc800_usb_probe (struct usb_interface *intf,

mdc800->state=READY;

- mutex_unlock(&mdc800->io_lock);
+ retval = usb_register_dev(intf, &mdc800_class);
+ if (retval) {
+ dev_err(&intf->dev, "Not able to get a minor for this device.\n");
+ return -ENODEV;
+ }

usb_set_intfdata(intf, mdc800);
return 0;
@@ -548,15 +543,12 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)

usb_deregister_dev(intf, &mdc800_class);

- /* must be under lock to make sure no URB
- is submitted after usb_kill_urb() */
- mutex_lock(&mdc800->io_lock);
mdc800->state=NOT_CONNECTED;

- usb_kill_urb(mdc800->irq_urb);
- usb_kill_urb(mdc800->write_urb);
- usb_kill_urb(mdc800->download_urb);
- mutex_unlock(&mdc800->io_lock);
+ usb_poison_urb(mdc800->irq_urb);
+ usb_poison_urb(mdc800->write_urb);
+ usb_poison_urb(mdc800->download_urb);
+

mdc800->dev = NULL;
usb_set_intfdata(intf, NULL);
--
2.55.0