WARNING in stub_timer (2)
Subsystems (3)
syzbot
syzbotHello,
syzbot found the following issue on:
HEAD commit: 9716c086c8e8 Merge tag 'pm-7.1-rc8' of git://git.kernel.or.. git tree: upstream console output: https://syzkaller.appspot.com/x/log.txt?x=120533d2580000 kernel config: https://syzkaller.appspot.com/x/.config?x=b4166e8ea5fbf7e3 dashboard link: https://syzkaller.appspot.com/bug?extid=5e8dda76ca21dae314b6 compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
Unfortunately, I don't have any reproducer for this issue yet.
Downloadable assets:
disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-9716c086.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/c42e123755c8/vmlinux-9716c086.xz
kernel image: https://storage.googleapis.com/syzbot-assets/4eb934549042/bzImage-9716c086.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
------------[ cut here ]------------ 1 WARNING: kernel/time/hrtimer.c:443 at stub_timer+0xa/0x20 kernel/time/timer.c:716, CPU#0: udevd/4706 Modules linked in: CPU: 0 UID: 0 PID: 4706 Comm: udevd Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:stub_timer+0xa/0x20 kernel/time/timer.c:716 Code: cc 66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa e8 d7 1a 13 00 90 <0f> 0b 90 31 c0 c3 cc cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 RSP: 0018:ffffc90000007dd0 EFLAGS: 00010006 RAX: ffffffff81b2ac39 RBX: 1ffff11000046617 RCX: ffff888000232540 RDX: 0000000000010000 RSI: ffffffff8c28d0c0 RDI: ffffc9000255fb20 RBP: ffffc9000255fb20 R08: ffffffff90305bf7 R09: 1ffffffff2060b7e R10: dffffc0000000000 R11: ffffffff81b2ac30 R12: ffff8880002330b8 R13: 1ffff11003f8506a R14: dffffc0000000000 R15: ffffffff81b2ac30 FS: 00007f6e41fb1880(0000) GS:ffff88808c894000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00005589b464e660 CR3: 00000000128d0000 CR4: 0000000000352ef0 Call Trace: <IRQ> __run_hrtimer kernel/time/hrtimer.c:1930 [inline] __hrtimer_run_queues+0x3c0/0xa20 kernel/time/hrtimer.c:1994 hrtimer_interrupt+0x44b/0x950 kernel/time/hrtimer.c:2113 local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1050 [inline] __sysvec_apic_timer_interrupt+0x102/0x430 arch/x86/kernel/apic/apic.c:1067 instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1061 [inline] sysvec_apic_timer_interrupt+0xa1/0xc0 arch/x86/kernel/apic/apic.c:1061 </IRQ> <TASK> asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697 RIP: 0010:__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:179 [inline] RIP: 0010:_raw_spin_unlock_irqrestore+0x47/0x80 kernel/locking/spinlock.c:198 Code: f7 e8 ad 28 f6 f5 f7 c3 00 02 00 00 74 05 e8 20 d2 21 f6 9c 58 a9 00 02 00 00 75 27 f7 c3 00 02 00 00 74 01 fb bf 01 00 00 00 <e8> c4 a7 e7 f5 65 8b 05 8d 9d 8c 07 85 c0 74 18 5b 41 5e c3 cc cc RSP: 0018:ffffc9000255fac8 EFLAGS: 00000206 RAX: 0000000000000006 RBX: 0000000000000246 RCX: 0000000080000001 RDX: 0000000000000000 RSI: ffffffff8dfa9d91 RDI: 0000000000000001 RBP: ffffc9000255fbf0 R08: ffffffff90305bf7 R09: 1ffffffff2060b7e R10: dffffc0000000000 R11: fffffbfff2060b7f R12: 1ffff920004abfae R13: 1ffff920004abf60 R14: ffff88801fc28280 R15: dffffc0000000000 schedule_hrtimeout_range_clock+0x142/0x330 kernel/time/sleep_timeout.c:213 ep_poll fs/eventpoll.c:2030 [inline] do_epoll_wait+0xd36/0xf60 fs/eventpoll.c:2464 __do_sys_epoll_wait fs/eventpoll.c:2472 [inline] __se_sys_epoll_wait fs/eventpoll.c:2467 [inline] __x64_sys_epoll_wait+0x1d7/0x230 fs/eventpoll.c:2467 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f6e418a7407 Code: 48 89 fa 4c 89 df e8 38 aa 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff RSP: 002b:00007ffe8bec5c00 EFLAGS: 00000202 ORIG_RAX: 00000000000000e8 RAX: ffffffffffffffda RBX: 00007f6e41fb1880 RCX: 00007f6e418a7407 RDX: 0000000000000008 RSI: 00007ffe8bec5d60 RDI: 000000000000000b RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000bb8 R11: 0000000000000202 R12: 0000000000000000 R13: 0000556a1ef48100 R14: 0000000000000000 R15: 0000000000000000 </TASK> ---------------- Code disassembly (best guess): 0: f7 e8 imul %eax 2: ad lods %ds:(%rsi),%eax 3: 28 f6 sub %dh,%dh 5: f5 cmc 6: f7 c3 00 02 00 00 test $0x200,%ebx c: 74 05 je 0x13 e: e8 20 d2 21 f6 call 0xf621d233 13: 9c pushf 14: 58 pop %rax 15: a9 00 02 00 00 test $0x200,%eax 1a: 75 27 jne 0x43 1c: f7 c3 00 02 00 00 test $0x200,%ebx 22: 74 01 je 0x25 24: fb sti 25: bf 01 00 00 00 mov $0x1,%edi * 2a: e8 c4 a7 e7 f5 call 0xf5e7a7f3 <-- trapping instruction 2f: 65 8b 05 8d 9d 8c 07 mov %gs:0x78c9d8d(%rip),%eax # 0x78c9dc3 36: 85 c0 test %eax,%eax 38: 74 18 je 0x52 3a: 5b pop %rbx 3b: 41 5e pop %r14 3d: c3 ret 3e: cc int3 3f: cc int3
---
This report is generated by a bot. It may contain errors. See https://goo.gl/tpsmEJ for more information about syzbot. syzbot engineers can be reached at [email protected].
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
Thomas Gleixner
maintainerQuoted 1 line · syzbot
WARNING: kernel/time/hrtimer.c:443 at stub_timer+0xa/0x20 kernel/time/timer.c:716, CPU#0: udevd/4706
So this puzzled me a bit as the stub_timer callback is only installed when the hrtimer object is not initialized according to the debug objects tracking. But that would cause a debug objects warning splat, which is not there.
Then I discovered this in the console log a few seconds before the warning:
ODEBUG: Out of memory. ODEBUG disabled
So that made me dig into debug_object_assert_init() and I discovered the following issue:
debug_assert_init()
if (!enabled)
return; obj = alloc();
if (!obj)
enabled = false;
free_objects();
obj = lookup_or_alloc();
// Lookup failed because the other side
// removed the objects, but it returns
// an error code as the object in question
// is not statically initialized
if (!IS_ERR_OR_NULL(obj))
return;
if (!obj) {
debug_oom();
return;
}
print(...)
if (!enabled)
return;
fixup(...)So invoking the fixup callback in that case without checking again whether debug_objects is still enabled causes the above problem.
Fix below.
Thanks,
tglx
---
lib/debugobjects.c +17 -0
@@ -894,6 +894,14 @@ int debug_object_activate(void *addr, const struct debug_obj_descr *descr) }raw_spin_unlock_irqrestore (&db->lock, flags); + +/* +* lookup_object_or_alloc() might have raced with a concurrent +* allocation failure which disabled debug objects. +*/ +if (!debug_objects_enabled) +return 0 ; +debug_print_object (&o,"activate" );switch (o.state) {
@@ -1071,6 +1079,15 @@ void debug_object_assert_init(void *addr, const struct debug_obj_descr *descr)return ; } +/* +* lookup_object_or_alloc() might have raced with a concurrent +* allocation failure which disabled debug objects. Don't run the fixup +* as it might turn a valid object useless. See for example +* hrtimer_fixup_assert_init(). +*/ +if (!debug_objects_enabled) +return ; +/* Object is neither tracked nor static. It's not initialized. */ debug_print_object (&o,"assert_init" );debug_object_fixup (descr->fixup_assert_init, addr,ODEBUG_STATE_NOTAVAILABLE );
Thomas Gleixner
maintainerPATCH 1/1 debugobjects: Plug race against a concurrent OOM disable
syzbot reported a puzzling splat:
WARNING: kernel/time/hrtimer.c:443 at stub_timer+0xa/0x20
stub_timer() is installed as timer callback function in hrtimer_fixup_assert_init(), which is invoked when debug_object_assert_init() can't find a shadow object. In that case debug objects emits a warning about it before invoking the fixup.
Though the provided console log lacks this warning and instead has the following a few seconds before the splat:
ODEBUG: Out of memory. ODEBUG disabled
So the object was looked up in debug_object_assert_init() and the lookup failed due a concurrent out of memory situation which disabled debug objects and freed the shadow objects:
debug_object_assert_init()
if (!debug_objects_enabled)
return; obj = alloc();
if (!obj) {
// Out of memory
debug_objects_enabled = false;
free_objects();
obj = lookup_or_alloc();
// The lookup failed because the other side
// removed the objects, so this returns
// an error code as the object in question
// is not statically initialized
if (!IS_ERR_OR_NULL(obj))
return;
if (!obj) {
debug_oom();
return;
}
print(...)
if (!debug_objects_enabled)
return;
fixup(...)The debug object splat is skipped because debug_objects_enabled is false, but the fixup callback is invoked unconditionally, which makes the timer disfunctional.
This is only a problem in debug_object_assert_init() and debug_object_activate() as both have to handle statically initialized objects and therefore must handle the error pointer return case gracefully. All other places only handle the found/not found case and the NULL pointer return is a signal for OOM. Otherwise they get a valid shadow object.
Plug the hole by checking whether debug objects are still enabled before invoking the print and fixup function in those two places.
--- lib/debugobjects.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
lib/debugobjects.c +17 -0
@@ -894,6 +894,14 @@ int debug_object_activate(void *addr, co }raw_spin_unlock_irqrestore (&db->lock, flags); + +/* +* lookup_object_or_alloc() might have raced with a concurrent +* allocation failure which disabled debug objects. +*/ +if (!debug_objects_enabled) +return 0 ; +debug_print_object (&o,"activate" );switch (o.state) {
@@ -1071,6 +1079,15 @@ void debug_object_assert_init(void *addrreturn ; } +/* +* lookup_object_or_alloc() might have raced with a concurrent +* allocation failure which disabled debug objects. Don't run the fixup +* as it might turn a valid object useless. See for example +* hrtimer_fixup_assert_init(). +*/ +if (!debug_objects_enabled) +return ; +/* Object is neither tracked nor static. It's not initialized. */ debug_print_object (&o,"assert_init" );debug_object_fixup (descr->fixup_assert_init, addr,ODEBUG_STATE_NOTAVAILABLE );
[tip: core/urgent] debugobjects: Plug race against a concurrent OOM disable
The following commit has been merged into the core/urgent branch of tip:
The following commit has been merged into the core/urgent branch of tip:
Commit-ID: b81dde13cc163450dcb402dcc915ef13ba241e01 Gitweb: https://git.kernel.org/tip/b81dde13cc163450dcb402dcc915ef13ba241e01 Author: Thomas Gleixner <[email protected]> AuthorDate: Sun, 21 Jun 2026 16:47:44 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 22 Jun 2026 16:38:57 +02:00
debugobjects: Plug race against a concurrent OOM disable
syzbot reported a puzzling splat:
WARNING: kernel/time/hrtimer.c:443 at stub_timer+0xa/0x20
stub_timer() is installed as timer callback function in hrtimer_fixup_assert_init(), which is invoked when debug_object_assert_init() can't find a shadow object. In that case debug objects emits a warning about it before invoking the fixup.
Though the provided console log lacks this warning and instead has the following a few seconds before the splat:
ODEBUG: Out of memory. ODEBUG disabled
So the object was looked up in debug_object_assert_init() and the lookup failed due a concurrent out of memory situation which disabled debug objects and freed the shadow objects:
debug_object_assert_init()
if (!debug_objects_enabled)
return; obj = alloc();
if (!obj) {
// Out of memory
debug_objects_enabled = false;
free_objects();
obj = lookup_or_alloc();
// The lookup failed because the other side
// removed the objects, so this returns
// an error code as the object in question
// is not statically initialized
if (!IS_ERR_OR_NULL(obj))
return;
if (!obj) {
debug_oom();
return;
}
print(...)
if (!debug_objects_enabled)
return;
fixup(...)The debug object splat is skipped because debug_objects_enabled is false, but the fixup callback is invoked unconditionally, which makes the timer disfunctional.
This is only a problem in debug_object_assert_init() and debug_object_activate() as both have to handle statically initialized objects and therefore must handle the error pointer return case gracefully. All other places only handle the found/not found case and the NULL pointer return is a signal for OOM. Otherwise they get a valid shadow object.
Plug the hole by checking whether debug objects are still enabled before invoking the print and fixup function in those two places.
--- lib/debugobjects.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
lib/debugobjects.c +17 -0
@@ -894,6 +894,14 @@ int debug_object_activate(void *addr, const struct debug_obj_descr *descr) }raw_spin_unlock_irqrestore (&db->lock, flags); + +/* +* lookup_object_or_alloc() might have raced with a concurrent +* allocation failure which disabled debug objects. +*/ +if (!debug_objects_enabled) +return 0 ; +debug_print_object (&o,"activate" );switch (o.state) {
@@ -1071,6 +1079,15 @@ void debug_object_assert_init(void *addr, const struct debug_obj_descr *descr)return ; } +/* +* lookup_object_or_alloc() might have raced with a concurrent +* allocation failure which disabled debug objects. Don't run the fixup +* as it might turn a valid object useless. See for example +* hrtimer_fixup_assert_init(). +*/ +if (!debug_objects_enabled) +return ; +/* Object is neither tracked nor static. It's not initialized. */ debug_print_object (&o,"assert_init" );debug_object_fixup (descr->fixup_assert_init, addr,ODEBUG_STATE_NOTAVAILABLE );