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: 4d16h, last: 4d16h
✨ 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
Based on kernel commit d135ab453a74:

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;
...
  1. 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).
  2. 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.
  3. The Race Condition:
    • If gb_operation_work() executes on another CPU before the calling thread in gb_operation_request_send() executes add_timer(&operation->timer):
      static void gb_operation_work(struct work_struct *work)
      {
          ...
          ret = timer_delete_sync(&operation->timer);
          ...
          operation->callback(operation);
          ...
          gb_operation_put_active(operation);
          gb_operation_put(operation);
      }
      
    • timer_delete_sync(&operation->timer) runs while the timer is not yet armed; it returns 0 and does nothing.
    • The original thread then runs add_timer(&operation->timer), linking operation->timer into the kernel timer wheel after the cleanup check has already passed.
    • Meanwhile, operation->callback() completes the operation (waking synchronous waiters if any, which release their reference via gb_operation_put()), and gb_operation_work() drops the remaining references with gb_operation_put().
    • When the refcount drops to 0, _gb_operation_destroy() frees the struct gb_operation slab object via kmem_cache_free(gb_operation_cache, operation).
  4. 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.
▶ ▼ ✨ AI Jobs (2)
ID Workflow Result Correct Bug Created Started Finished Revision
0fd37385 repro-c Reproduced: ✅ ❓ WARNING: ODEBUG bug in process_scheduled_works 2026/10/30 00:01 2026/10/30 00:01 2026/10/30 03:28 2dbcf159
07183a68 assessment-security DenialOfService: ✅ Exploitable: ✅ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ✅ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ✅ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ WARNING: ODEBUG bug in process_scheduled_works 2026/10/29 00:00 2026/10/29 00:00 2026/10/29 00:56 b1d00f76
▶ ▼ Last patch testing requests (1)
Created Duration User Patch Repo Result
2026/10/30 04:55 19m retest repro git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 4dd16e31135ea8437a720222df34e8745f385d6d no crash job log log

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

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/10/27 23:32 upstream d135ab453a74 96923c60 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-kasan-gce WARNING: ODEBUG bug in process_scheduled_works
* Struck through repros no longer work on HEAD.