syzbot
WARNING: ODEBUG bug in process_scheduled_works
Status:
moderation: reported on 2026/10/31 23:41
Subsystems:
kernel
Labels:
prio:high
[Documentation on labels]
Reported-by: syzbot+ca5cdb5da636f8275a80@syzkaller.appspotmail.com
First crash: 4d03h, last: 4d03h
✨ AI-generated root cause summary:
A race condition in drivers/greybus/operation.c allows gb_operation_request_send() to arm operation->timer after the operation has already completed or been cancelled and cleaned up by gb_operation_work(). Because timer_delete_sync() runs before add_timer(), the timer remains active in the kernel timer wheel when struct gb_operation is freed via kmem_cache_free(). In a production kernel without debug objects, this causes a use-after-free and kernel memory corruption upon timer expiry or timer wheel list manipulation.
▶
▼
✨ Full AI root cause analysis
Root Cause Analysis
1. Functions, Structs, Fields, and Files Involved
- Source File:
drivers/greybus/operation.c
- Functions:
gb_operation_request_send(), gb_operation_work(), _gb_operation_destroy()
- Structs & Fields:
struct gb_operation:
operation->timer (struct timer_list)
operation->work (struct work_struct)
operation->kref (struct kref)
operation->errno
2. Mechanism & Invariant Violation
In gb_operation_request_send() (drivers/greybus/operation.c):
int gb_operation_request_send(struct gb_operation *operation,
gb_operation_callback callback,
unsigned int timeout,
gfp_t gfp)
{
...
gb_operation_result_set(operation, -EINPROGRESS);
gb_operation_get(operation);
ret = gb_operation_get_active(operation);
if (ret)
goto err_put;
ret = gb_message_send(operation->request, gfp);
if (ret)
goto err_put_active;
if (timeout) {
operation->timer.expires = jiffies + msecs_to_jiffies(timeout);
add_timer(&operation->timer);
}
return 0;
...
- Premature Exposure: Once
gb_operation_get_active() and gb_message_send() execute, the operation is made active on the connection and dispatched to the host device. However, operation->timer is only armed after message transmission via add_timer(&operation->timer).
- Concurrent Completion/Cancellation: As soon as the operation is sent/active, it can complete or be cancelled asynchronously from another context (e.g., via
gb_connection_recv_response(), greybus_message_sent(), or gb_operation_cancel()). This sets the final result and schedules operation->work (gb_operation_work) on gb_operation_completion_wq.
- The Race Condition:
- Invariant Violated: A
struct timer_list embedded inside an allocated structure must be deactivated/deleted before the enclosing memory block is freed. In this race, operation->timer remains actively enrolled in the kernel's timer wheel when operation is returned to the slab allocator.
With CONFIG_DEBUG_OBJECTS=y, debug_check_no_obj_freed() intercepts the free in kmem_cache_free() and detects that the embedded timer_list at offset 0xd0 is still in the active state, emitting the ODEBUG: free active ... object type: timer_list hint: gb_operation_timeout warning.
3. Production Runtime Impact & Classification
- Memory Corruption (
MemoryCorruption = true):
In a production kernel without CONFIG_DEBUG_OBJECTS, struct gb_operation is freed while operation->timer remains linked into the per-CPU timer wheel list. When the timer expires, the kernel timer engine executes gb_operation_timeout(&operation->timer) on freed (or reallocated) memory, causing a use-after-free (UAF). Additionally, timer wheel list modifications on dangling node pointers cause heap memory corruption.
- Denial of Service (
RawDenialOfService = true):
The use-after-free or timer wheel list corruption will crash the kernel (kernel panic or general protection fault / oops) when the timer expires or when neighboring timers in the wheel list are processed.
- Information Leak (
InfoLeak = "none"):
No uninitialized kernel memory or kernel pointers are leaked or copied back to userspace or external entities.
- Virtualization / KVM (
IsKVMCandidate = false):
The bug is entirely within the Greybus subsystem and does not touch KVM, hypervisors, or virtualization devices.
- Networking (
IsNetCandidate = false):
Greybus is a hardware bus protocol/architecture (UniPro application layer) and does not involve network protocols, sockets, or network devices.
▶
▼
Last patch testing requests (1)
Sample crash report:
------------[ cut here ]------------
ODEBUG: free active (active state 0) object: ffff888042c543e0 object type: timer_list hint: gb_operation_timeout+0x0/0x110 drivers/greybus/operation.c:1265
WARNING: lib/debugobjects.c:632 at debug_print_object+0xec/0x230 lib/debugobjects.c:629, CPU#1: kworker/1:3/15187
Modules linked in:
CPU: 1 UID: 0 PID: 15187 Comm: kworker/1:3 Tainted: G L syzkaller #0 PREEMPT(full)
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/16/2026
Workqueue: greybus_completion gb_operation_work
RIP: 0010:debug_print_object+0x18a/0x230 lib/debugobjects.c:629
Code: f8 48 c1 e8 03 80 3c 18 00 74 08 4c 89 ff e8 3d cb 47 fd 4d 8b 0f 4c 89 ef 48 8b 74 24 08 48 89 ea 44 89 e1 4d 89 f0 ff 34 24 <67> 48 0f b9 3a 48 83 c4 08 ff 05 a3 a7 a5 0c 48 83 c4 10 5b 41 5c
RSP: 0018:ffffc90003bb7980 EFLAGS: 00010246
RAX: 1ffffffff185f420 RBX: dffffc0000000000 RCX: 0000000000000000
RDX: ffffffff8c8e7d40 RSI: ffffffff8c8e77c0 RDI: ffffffff91a85a90
RBP: ffffffff8c8e7d40 R08: ffff888042c543e0 R09: ffffffff8c2fb460
R10: dffffc0000000000 R11: ffffffff81b4d940 R12: 0000000000000000
R13: ffffffff91a85a90 R14: ffff888042c543e0 R15: ffffffff8c2fa100
FS: 0000000000000000(0000) GS:ffff88812372d000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000001b32f01ff8 CR3: 0000000080c26000 CR4: 00000000003526f0
Call Trace:
<TASK>
__debug_check_no_obj_freed lib/debugobjects.c:1171 [inline]
debug_check_no_obj_freed+0x2e3/0x450 lib/debugobjects.c:1201
slab_free_hook mm/slub.c:2711 [inline]
slab_free mm/slub.c:6630 [inline]
kmem_cache_free+0xfd/0x650 mm/slub.c:6757
process_one_work kernel/workqueue.c:3495 [inline]
process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3578
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3659
kthread+0x38b/0x480 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
----------------
Code disassembly (best guess):
0: f8 clc
1: 48 c1 e8 03 shr $0x3,%rax
5: 80 3c 18 00 cmpb $0x0,(%rax,%rbx,1)
9: 74 08 je 0x13
b: 4c 89 ff mov %r15,%rdi
e: e8 3d cb 47 fd call 0xfd47cb50
13: 4d 8b 0f mov (%r15),%r9
16: 4c 89 ef mov %r13,%rdi
19: 48 8b 74 24 08 mov 0x8(%rsp),%rsi
1e: 48 89 ea mov %rbp,%rdx
21: 44 89 e1 mov %r12d,%ecx
24: 4d 89 f0 mov %r14,%r8
27: ff 34 24 push (%rsp)
* 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
2f: 48 83 c4 08 add $0x8,%rsp
33: ff 05 a3 a7 a5 0c incl 0xca5a7a3(%rip) # 0xca5a7dc
39: 48 83 c4 10 add $0x10,%rsp
3d: 5b pop %rbx
3e: 41 5c pop %r12
* Struck through repros no longer work on HEAD.