All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] mmc: vub300: fix sleeping function called from invalid context
@ 2026-08-07  3:36 syzbot
  0 siblings, 0 replies; only message in thread
From: syzbot @ 2026-08-07  3:36 UTC (permalink / raw)
  To: syzkaller-upstream-moderation; +Cc: syzbot

The vub300 driver manages an inactivity timer that holds a reference to the
vub300 object. When the timer expires and the interface is disconnected
(!vub300->interface), the timer callback drops the reference. If this is
the last reference, it triggers vub300_delete(), which calls
mmc_free_host(). Since mmc_free_host() can sleep (e.g., calling
cancel_delayed_work_sync()), calling it from the timer's softirq context
causes a "sleeping function called from invalid context" BUG.

BUG: sleeping function called from invalid context at
kernel/workqueue.c:4487
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 0, name: swapper/1
Preemption disabled at:
[<0000000000000000>] 0x0
CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Not tainted
Call Trace:
 <IRQ>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 __might_resched+0x378/0x4d0 kernel/sched/core.c:9197
 __cancel_work_sync+0x6d/0x110 kernel/workqueue.c:4487
 mmc_free_host+0x19/0x30 drivers/mmc/core/host.c:700
 call_timer_fn+0x192/0x5e0 kernel/time/timer.c:1748
 expire_timers kernel/time/timer.c:1799 [inline]
 __run_timers kernel/time/timer.c:2374 [inline]
 __run_timer_base+0x652/0x8b0 kernel/time/timer.c:2386
 run_timer_base kernel/time/timer.c:2395 [inline]
 run_timer_softirq+0xb7/0x170 kernel/time/timer.c:2405
 handle_softirqs+0x225/0x840 kernel/softirq.c:622
 __do_softirq kernel/softirq.c:656 [inline]
 invoke_softirq kernel/softirq.c:496 [inline]
 __irq_exit_rcu+0xca/0x220 kernel/softirq.c:735
 irq_exit_rcu+0x9/0x30 kernel/softirq.c:752
 instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1062
 [inline]
 sysvec_apic_timer_interrupt+0xa6/0xc0 arch/x86/kernel/apic/apic.c:1062
 </IRQ>

To fix this, decouple the timer from the object's reference counting. The
timer does not need to hold a reference to the vub300 object if we ensure
it is synchronously stopped before the object is freed. Remove the
kref_get() and kref_put() associated with the inactivity_timer, and
explicitly call timer_delete_sync() in vub300_disconnect() and the probe
error path. Since vub300->interface is set to NULL before
timer_delete_sync(), any concurrently running timer will simply exit,
allowing the synchronous wait to complete safely.

Additionally, fix similar issues with sg_transfer_timer. In
__command_read_data() and __command_write_data(), replace timer_delete()
with timer_delete_sync() to prevent the timer callback from running
concurrently after the function returns. In __command_write_data(), ensure
the timer is unconditionally stopped even if an error occurs.

Fixes: 88095e7b473a ("mmc: Add new VUB300 USB-to-SD/SDIO/MMC driver")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: syzbot+0e06aa1bdc6495bac24b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=0e06aa1bdc6495bac24b
Link: https://syzkaller.appspot.com/ai_job?id=dcef6af0-9740-47ea-949c-72048301deb8
To: <linux-mmc@vger.kernel.org>
To: "Ulf Hansson" <ulfh@kernel.org>
To: "Tony Olech" <tony.olech@elandigitalsystems.com>
Cc: "Johan Hovold" <johan@kernel.org>
Cc: "Guangshuo Li" <lgs201920130244@gmail.com>
Cc: <linux-kernel@vger.kernel.org>
Cc: "Runyu Xiao" <runyu.xiao@seu.edu.cn>

---
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 2dae474dc..9b08755cc 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -744,7 +744,7 @@ static void vub300_inactivity_timer_expired(struct timer_list *t)
 	struct vub300_mmc_host *vub300 = timer_container_of(vub300, t,
 							    inactivity_timer);
 	if (!vub300->interface) {
-		kref_put(&vub300->kref, vub300_delete);
+		/* timer_delete_sync() will wait for us */
 	} else if (vub300->cmd) {
 		mod_timer(&vub300->inactivity_timer, jiffies + HZ);
 	} else {
@@ -1453,7 +1453,7 @@ static int __command_read_data(struct vub300_mmc_host *vub300,
 						  (linear_length / 16384));
 			add_timer(&vub300->sg_transfer_timer);
 			usb_sg_wait(&vub300->sg_request);
-			timer_delete(&vub300->sg_transfer_timer);
+			timer_delete_sync(&vub300->sg_transfer_timer);
 			if (vub300->sg_request.status < 0) {
 				cmd->error = vub300->sg_request.status;
 				data->bytes_xfered = 0;
@@ -1570,10 +1570,10 @@ static int __command_write_data(struct vub300_mmc_host *vub300,
 							   linear_length / 16384);
 			add_timer(&vub300->sg_transfer_timer);
 			usb_sg_wait(&vub300->sg_request);
+			timer_delete_sync(&vub300->sg_transfer_timer);
 			if (cmd->error) {
 				data->bytes_xfered = 0;
 			} else {
-				timer_delete(&vub300->sg_transfer_timer);
 				if (vub300->sg_request.status < 0) {
 					cmd->error = vub300->sg_request.status;
 					data->bytes_xfered = 0;
@@ -2327,7 +2327,6 @@ static int vub300_probe(struct usb_interface *interface,
 	INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
 	kref_init(&vub300->kref);
 	timer_setup(&vub300->sg_transfer_timer, vub300_sg_timed_out, 0);
-	kref_get(&vub300->kref);
 	timer_setup(&vub300->inactivity_timer,
 		    vub300_inactivity_timer_expired, 0);
 	vub300->inactivity_timer.expires = jiffies + HZ;
@@ -2350,6 +2349,7 @@ static int vub300_probe(struct usb_interface *interface,
 
 err_stop_io:
 	vub300->interface = NULL;
+	timer_delete_sync(&vub300->inactivity_timer);
 	kref_put(&vub300->kref, vub300_delete);
 
 	return retval;
@@ -2385,6 +2385,7 @@ static void vub300_disconnect(struct usb_interface *interface)
 			/* prevent more I/O from starting */
 			vub300->interface = NULL;
 			mmc_remove_host(mmc);
+			timer_delete_sync(&vub300->inactivity_timer);
 			kref_put(&vub300->kref, vub300_delete);
 			pr_info("USB vub300 remote SDIO host controller[%d]"
 				" now disconnected", ifnum);


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 syzkaller@googlegroups.com.

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-07  3:36 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-07  3:36 [PATCH RFC] mmc: vub300: fix sleeping function called from invalid context syzbot

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.