The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Yunseong Kim <ysk@kzalloc.com>
To: gregkh@linuxfoundation.org, stern@rowland.harvard.edu,
	linux-usb@vger.kernel.org
Cc: "Thomas Gleixner" <tglx@linutronix.de>,
	"Sebastian Andrzej Siewior" <bigeasy@linutronix.de>,
	"Clark Williams" <clrkwllms@kernel.org>,
	"Steven Rostedt" <rostedt@goodmis.org>,
	"Nam Cao" <namcao@linutronix.de>,
	"Marcello Sylvester Bauer" <sylv@sylv.io>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski@linaro.org>,
	"Uwe Kleine-König" <u.kleine-koenig@baylibre.com>,
	"Al Viro" <viro@zeniv.linux.org.uk>,
	andreyknvl@gmail.com, "Austin Kim" <austindh.kim@gmail.com>,
	linux-rt-users@vger.kernel.org, linux-kernel@vger.kernel.org,
	syzkaller@googlegroups.com
Subject: [BUG] usb: gadget: dummy_hcd: Sleeping function called from invalid context in dummy_dequeue on PREEMPT_RT
Date: Sat, 16 Aug 2025 11:38:14 +0900	[thread overview]
Message-ID: <5b337389-73b9-4ee4-a83e-7e82bf5af87a@kzalloc.com> (raw)

While testing a PREEMPT_RT enabled kernel (based on v6.17.0-rc1),
I encountered a "BUG: sleeping function called from invalid context" error
originating from the dummy_dequeue function in the dummy USB driver.

The call flow (triggered via ioctl):

  Userspace (syz.0.2514 via ioctl)
      |
      v
  raw_ioctl() -> usb_ep_dequeue()
      |
      v
  dummy_dequeue() [drivers/usb/gadget/udc/dummy_hcd.c]
      |
      |     (Context: Process Context, IRQs Enabled)
      |
      |---> local_irq_save(flags);
      |
      |     *** STATE CHANGE: IRQs Disabled (Atomic Context) ***
      |
      |---> spin_lock(&dum->lock);  <--- Trace location (dummy_hcd.c:769)
            |
            | [On PREEMPT_RT]
            v
            rt_spin_lock() [kernel/locking/spinlock_rt.c]
            |
            v
            [May Sleep if contended]
            |
      X <--- BUG: Sleeping in atomic context!

      |
      |---> spin_unlock(&dum->lock);
      |
      |     (Note: IRQs are still disabled here)
      |
      |---> usb_gadget_giveback_request();
      |
      v
      local_irq_restore(flags);
      (Context: IRQs Enabled)

Stack trace excerpt:

 BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
 in_atomic(): 0, irqs_disabled(): 1, non_block: 0, pid: 27291, name: syz.0.2514
 preempt_count: 0, expected: 0
 RCU nest depth: 0, expected: 0
 CPU: 1 UID: 0 PID: 27291 Comm: syz.0.2514 Kdump: loaded Not tainted 6.17.0-rc1-00001-g1149a5db27c8-dirty #55 PREEMPT_RT 
 Hardware name: QEMU KVM Virtual Machine, BIOS 2025.02-8ubuntu1 06/11/2025
 Call trace:
  show_stack+0x2c/0x3c arch/arm64/kernel/stacktrace.c:499 (C)
  __dump_stack+0x30/0x40 lib/dump_stack.c:94
  dump_stack_lvl+0x148/0x1d8 lib/dump_stack.c:120
  dump_stack+0x1c/0x3c lib/dump_stack.c:129
  __might_resched+0x2e4/0x52c kernel/sched/core.c:8957
  __rt_spin_lock kernel/locking/spinlock_rt.c:48 [inline]
  rt_spin_lock+0xa8/0x1bc kernel/locking/spinlock_rt.c:57
  spin_lock include/linux/spinlock_rt.h:44 [inline]
  dummy_dequeue+0x9c/0x3b8 drivers/usb/gadget/udc/dummy_hcd.c:769
  usb_ep_dequeue+0x70/0x21c drivers/usb/gadget/udc/core.c:330
  raw_process_ep0_io+0x2e8/0x704 drivers/usb/gadget/legacy/raw_gadget.c:738
  raw_ioctl_ep0_write drivers/usb/gadget/legacy/raw_gadget.c:766 [inline]
  raw_ioctl+0x1b44/0x3288 drivers/usb/gadget/legacy/raw_gadget.c:1312
  vfs_ioctl fs/ioctl.c:51 [inline]
  __do_sys_ioctl fs/ioctl.c:598 [inline]
  __se_sys_ioctl fs/ioctl.c:584 [inline]
  __arm64_sys_ioctl+0x14c/0x1c4 fs/ioctl.c:584
  __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
  invoke_syscall+0x98/0x2b8 arch/arm64/kernel/syscall.c:49
  el0_svc_common+0x130/0x23c arch/arm64/kernel/syscall.c:132
  do_el0_svc+0x48/0x58 arch/arm64/kernel/syscall.c:151
  el0_svc+0x40/0x140 arch/arm64/kernel/entry-common.c:879
  el0t_64_sync_handler+0x84/0x12c arch/arm64/kernel/entry-common.c:898
  el0t_64_sync+0x1ac/0x1b0 arch/arm64/kernel/entry.S:596

On PREEMPT_RT configurations, spin_lock() is replaced by rt_spin_lock(),
which may sleep when contended. Therefore, it is forbidden to call
spin_lock() while interrupts are hard-disabled (atomic context).

The issue occurs in dummy_dequeue because it explicitly disables interrupts
using local_irq_save() before attempting to acquire dum->lock via
spin_lock().

static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
    // ... (snip) ...
    ep = usb_ep_to_dummy_ep(_ep);
    dum = ep_to_dummy(ep);

    if (!dum->driver)
        return -ESHUTDOWN;

    local_irq_save(flags);       // <--- 1. IRQs Disabled (Enters Atomic Context)
    spin_lock(&dum->lock);       // <--- 2. Calls rt_spin_lock (May sleep) -> BUG
    list_for_each_entry(iter, &ep->queue, queue) {
        // ... (critical section) ...
        break;
    }
    spin_unlock(&dum->lock);

    if (retval == 0) {
        // ... (snip) ...
        // Note: Called while IRQs are still disabled.
        usb_gadget_giveback_request(_ep, _req);
    }
    local_irq_restore(flags);    // <--- 3. IRQs restored
    return retval;
}

The pattern of manually disabling IRQs and then taking a spinlock
local_irq_save() + spin_lock() is unsafe on PREEMPT_RT, the current code
structure keeps IRQs disabled even after spin_unlock(&dum->lock) while
calling usb_gadget_giveback_request(). This extended atomic context can
also be problematic if the completion handler attempts to acquire another
sleepable lock.

I request a review and correction of this locking mechanism to ensure
stability on PREEMPT_RT configurations.  Kernel config, full logs, and
reproduction steps can be provided on request.

Thanks,

Best Regards,
Yunseong Kim

             reply	other threads:[~2025-08-16  2:38 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-16  2:38 Yunseong Kim [this message]
2025-08-16  6:59 ` [BUG] usb: gadget: dummy_hcd: Sleeping function called from invalid context in dummy_dequeue on PREEMPT_RT Nam Cao
2025-08-16 11:41   ` Yunseong Kim
2025-08-19 10:21   ` Sebastian Andrzej Siewior

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=5b337389-73b9-4ee4-a83e-7e82bf5af87a@kzalloc.com \
    --to=ysk@kzalloc.com \
    --cc=andreyknvl@gmail.com \
    --cc=austindh.kim@gmail.com \
    --cc=bigeasy@linutronix.de \
    --cc=clrkwllms@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=krzysztof.kozlowski@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-users@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=namcao@linutronix.de \
    --cc=rostedt@goodmis.org \
    --cc=stern@rowland.harvard.edu \
    --cc=sylv@sylv.io \
    --cc=syzkaller@googlegroups.com \
    --cc=tglx@linutronix.de \
    --cc=u.kleine-koenig@baylibre.com \
    --cc=viro@zeniv.linux.org.uk \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox