[syzbot] [net?] WARNING: ODEBUG bug in lane_ioctl (3)

2 views
Skip to first unread message

syzbot

unread,
Apr 28, 2026, 10:25:47 PM (2 days ago) Apr 28
to da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux-...@vger.kernel.org, net...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
Hello,

syzbot found the following issue on:

HEAD commit: e728258debd5 Merge tag 'net-7.1-rc1' of git://git.kernel.o..
git tree: net-next
console output: https://syzkaller.appspot.com/x/log.txt?x=1752f702580000
kernel config: https://syzkaller.appspot.com/x/.config?x=ca77bfc4078c8193
dashboard link: https://syzkaller.appspot.com/bug?extid=ca9d5686d06994c6547c
compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=16811c36580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=128c52d2580000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/24195bde5d1d/disk-e728258d.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/78131d1b0e14/vmlinux-e728258d.xz
kernel image: https://storage.googleapis.com/syzbot-assets/836d0dd78c10/bzImage-e728258d.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+ca9d56...@syzkaller.appspotmail.com

------------[ cut here ]------------
ODEBUG: init active (active state 0) object: ffff888077a60f78 object type: timer_list hint: lec_arp_check_expire+0x0/0xc90 net/atm/lec.c:-1
WARNING: lib/debugobjects.c:632 at debug_print_object lib/debugobjects.c:629 [inline], CPU#0: syz-executor253/5933
WARNING: lib/debugobjects.c:632 at __debug_object_init+0x2b1/0x4e0 lib/debugobjects.c:780, CPU#0: syz-executor253/5933
Modules linked in:
CPU: 0 UID: 0 PID: 5933 Comm: syz-executor253 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
RIP: 0010:debug_print_object lib/debugobjects.c:629 [inline]
RIP: 0010:__debug_object_init+0x30f/0x4e0 lib/debugobjects.c:780
Code: 3c 38 00 74 08 4c 89 ef e8 0e df 74 fd 4d 8b 4d 00 4c 89 f7 48 c7 c6 20 a7 28 8c 4c 89 e2 8b 4c 24 08 4c 8b 04 24 ff 74 24 10 <67> 48 0f b9 3a 48 83 c4 08 ff 05 8e 8c 77 0b 83 fd 03 75 3f 4c 8b
RSP: 0018:ffffc90003e278f8 EFLAGS: 00010246
RAX: 1ffffffff179e734 RBX: ffff888077a60f78 RCX: 0000000000000000
RDX: ffffffff8c28ab20 RSI: ffffffff8c28a720 RDI: ffffffff903e69a0
RBP: 0000000000000003 R08: ffff888077a60f78 R09: ffffffff8bcf4d00
R10: dffffc0000000000 R11: ffffffff81b236d0 R12: ffffffff8c28ab20
R13: ffffffff8bcf39a0 R14: ffffffff903e69a0 R15: dffffc0000000000
FS: 00007f3e1e8976c0(0000) GS:ffff888125213000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055a602110fd8 CR3: 00000000753ea000 CR4: 00000000003526f0
Call Trace:
<TASK>
debug_timer_init kernel/time/timer.c:788 [inline]
debug_init kernel/time/timer.c:836 [inline]
timer_init_key+0x41/0x2c0 kernel/time/timer.c:880
lec_arp_init net/atm/lec.c:1274 [inline]
lecd_attach net/atm/lec.c:781 [inline]
lane_ioctl+0x1579/0x2220 net/atm/lec.c:1037
do_vcc_ioctl+0x36d/0x9d0 net/atm/ioctl.c:159
svc_ioctl+0x1f6/0x7d0 net/atm/svc.c:611
sock_do_ioctl+0x101/0x320 net/socket.c:1313
sock_ioctl+0x5c6/0x7f0 net/socket.c:1434
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f3e1e8bf0d9
Code: c0 79 93 eb d5 48 8d 7c 1d 00 eb 99 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 d0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f3e1e897158 EFLAGS: 00000246
ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f3e1e96fb48 RCX: 00007f3e1e8bf0d9
RDX: 0000000000000000 RSI: 00000000000061d0 RDI: 0000000000000005
RBP: 00007f3e1e96fb40 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00007f3e1e9413b0
R13: 0000000000000000 R14: 0000200000000040 R15: b635773f07ebbeef
</TASK>
----------------
Code disassembly (best guess):
0: 3c 38 cmp $0x38,%al
2: 00 74 08 4c add %dh,0x4c(%rax,%rcx,1)
6: 89 ef mov %ebp,%edi
8: e8 0e df 74 fd call 0xfd74df1b
d: 4d 8b 4d 00 mov 0x0(%r13),%r9
11: 4c 89 f7 mov %r14,%rdi
14: 48 c7 c6 20 a7 28 8c mov $0xffffffff8c28a720,%rsi
1b: 4c 89 e2 mov %r12,%rdx
1e: 8b 4c 24 08 mov 0x8(%rsp),%ecx
22: 4c 8b 04 24 mov (%rsp),%r8
26: ff 74 24 10 push 0x10(%rsp)
* 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
2f: 48 83 c4 08 add $0x8,%rsp
33: ff 05 8e 8c 77 0b incl 0xb778c8e(%rip) # 0xb778cc7
39: 83 fd 03 cmp $0x3,%ebp
3c: 75 3f jne 0x7d
3e: 4c rex.WR
3f: 8b .byte 0x8b


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

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 syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

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

Arjan van de Ven

unread,
Apr 29, 2026, 11:16:37 AM (21 hours ago) Apr 29
to net...@vger.kernel.org, syzbot+ca9d56...@syzkaller.appspotmail.com, da...@davemloft.net, edum...@google.com, ho...@kernel.org, ku...@kernel.org, linux-...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com, Arjan van de Ven
This email is created by automation to help kernel developers deal with
a large volume of bug reports by decoding oopses into more actionable
information.


Decoded Backtrace

1. __debug_object_init -- crash site (lib/debugobjects.c:632)

The WARN fires inside debug_print_object (inlined into
__debug_object_init). The object at 0xffff888077a60f78 (a timer_list) is
in the ACTIVE state when debug_object_init is called on it a second time.

611 static void debug_print_object(struct debug_obj *obj, char *msg)
612 {
613 const struct debug_obj_descr *descr = obj->descr;
614 static int limit;
622 if (!debug_objects_enabled)
623 return;
625 if (limit < 5 && descr != descr_test) {
626 void *hint = descr->debug_hint ?
627 descr->debug_hint(obj->object) : NULL;
628 limit++;
-> 629 WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "
630 "object: %p object type: %s hint: %pS\n",
631 msg, obj_states[obj->state], obj->astate,
632 obj->object, descr->name, hint);
633 }
634 debug_objects_warnings++;
635 }

747 static void
748 __debug_object_init(void *addr, const struct debug_obj_descr *descr,
749 int onstack)
750 {
751 struct debug_obj *obj, o;
752 struct debug_bucket *db;
753 unsigned long flags;
755 debug_objects_fill_pool();
757 db = get_bucket((unsigned long) addr);
759 raw_spin_lock_irqsave(&db->lock, flags);
761 obj = lookup_object_or_alloc(addr, db, descr, onstack, false);
762 if (unlikely(!obj)) {
763 raw_spin_unlock_irqrestore(&db->lock, flags);
764 debug_objects_oom();
765 return;
766 }
768 switch (obj->state) {
769 case ODEBUG_STATE_NONE:
770 case ODEBUG_STATE_INIT:
771 case ODEBUG_STATE_INACTIVE:
772 obj->state = ODEBUG_STATE_INIT;
773 raw_spin_unlock_irqrestore(&db->lock, flags);
774 return;
775 default:
776 break;
777 }
779 o = *obj;
780 raw_spin_unlock_irqrestore(&db->lock, flags);
-> 780 debug_print_object(&o, "init");
783 if (o.state == ODEBUG_STATE_ACTIVE)
784 debug_object_fixup(descr->fixup_init, addr, o.state);
785 }


2. timer_init_key -- kernel/time/timer.c:880

786 static inline void debug_timer_init(struct timer_list *timer)
787 {
-> 788 debug_object_init(timer, &timer_debug_descr);
789 }

834 static inline void debug_init(struct timer_list *timer)
835 {
-> 836 debug_timer_init(timer);
837 trace_timer_init(timer);
838 }

876 void timer_init_key(struct timer_list *timer,
877 void (*func)(struct timer_list *), unsigned int flags,
878 const char *name, struct lock_class_key *key)
879 {
-> 880 debug_init(timer);
881 do_init_timer(timer, func, flags, name, key);
882 }


3. lane_ioctl / lecd_attach / lec_arp_init (net/atm/lec.c:1037)

1264 static void lec_arp_init(struct lec_priv *priv)
1265 {
1266 unsigned short i;
1268 for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
1269 INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
1270 INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
1271 INIT_HLIST_HEAD(&priv->lec_no_forward);
1272 INIT_HLIST_HEAD(&priv->mcast_fwds);
1273 spin_lock_init(&priv->lec_arp_lock);
->1274 INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire);
1275 schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
1276 }

748 static int lecd_attach(struct atm_vcc *vcc, int arg)
749 {
750 int i;
751 struct lec_priv *priv;
753 lockdep_assert_held(&lec_mutex);
754 if (arg < 0)
755 arg = 0;
756 if (arg >= MAX_LEC_ITF)
757 return -EINVAL;
758 i = array_index_nospec(arg, MAX_LEC_ITF);
759 if (!dev_lec[i]) {
763 dev_lec[i] = alloc_etherdev(size);
775 priv = netdev_priv(dev_lec[i]);
776 } else {
776 priv = netdev_priv(dev_lec[i]);
777 if (rcu_access_pointer(priv->lecd))
778 return -EADDRINUSE;
779 }
->781 lec_arp_init(priv); // called unconditionally for both new and
// existing priv -- no work cancellation

1018 static int lane_ioctl(struct socket *sock, unsigned int cmd,
1019 unsigned long arg)
1020 {
1034 mutex_lock(&lec_mutex);
1035 switch (cmd) {
1036 case ATMLEC_CTRL:
->1037 err = lecd_attach(vcc, (int)arg);
1038 if (err >= 0)
1039 sock->state = SS_CONNECTED;
1040 break;
1049 mutex_unlock(&lec_mutex);
1050 return err;
1051 }


4. do_vcc_ioctl (net/atm/ioctl.c:159)

153 error = -ENOIOCTLCMD;
155 mutex_lock(&ioctl_mutex);
156 list_for_each(pos, &ioctl_list) {
157 struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
158 if (try_module_get(ic->owner)) {
->159 error = ic->ioctl(sock, cmd, arg); // dispatches to lane_ioctl
160 module_put(ic->owner);
161 if (error != -ENOIOCTLCMD)
162 break;
163 }
164 }
165 mutex_unlock(&ioctl_mutex);


Tentative Analysis

The ODEBUG WARNING fires when INIT_DELAYED_WORK() is called on a
timer_list (lec_priv.lec_arp_work) that is already in the ACTIVE state.

lec_arp_init() always calls INIT_DELAYED_WORK(&priv->lec_arp_work, ...)
followed by schedule_delayed_work(). lecd_attach() calls lec_arp_init()
unconditionally -- both for a brand-new device and for an existing one
in the else-branch. The only guard for the existing-device path is that
priv->lecd is NULL (no daemon currently attached).

The race is opened by lec_atm_close(), the ATM VCC close handler:

Thread A (lec_atm_close): Thread B (lecd_attach via lane_ioctl):
rcu_assign_pointer(lecd, NULL)
synchronize_rcu() mutex_lock(&lec_mutex)
[window open] sees priv->lecd == NULL -- passes guard
lec_arp_init(priv)
INIT_DELAYED_WORK on active timer
--> ODEBUG WARN
lec_arp_destroy(priv) [too late: work already re-initialized]

lec_atm_close() clears priv->lecd to NULL *before* calling
lec_arp_destroy() (which contains cancel_delayed_work_sync). Because
lec_atm_close() does not hold lec_mutex, Thread B can observe
priv->lecd == NULL while lec_arp_work is still active, pass the guard
in lecd_attach(), and call lec_arp_init() on a live timer.

The lec_mutex protecting dev_lec[] was introduced by commit d13a3824bfd2
("net: atm: add lec_mutex"), which serialised lecd_attach() and friends
but did not update lec_atm_close() to also acquire the mutex. The
unconditional lec_arp_init() call for existing devices predates that
commit and has always been present.


Potential Solution

Add cancel_delayed_work_sync(&priv->lec_arp_work) in the else-branch of
lecd_attach(), immediately before the call to lec_arp_init(). This
ensures any in-flight work is drained before the timer is re-initialized,
regardless of whether lec_atm_close() has already cancelled it.
cancel_delayed_work_sync() is safe to call from a lec_mutex-held context
because lec_arp_check_expire() only acquires priv->lec_arp_lock (a
spinlock) and never tries to take lec_mutex.

} else {
priv = netdev_priv(dev_lec[i]);
if (rcu_access_pointer(priv->lecd))
return -EADDRINUSE;
+ cancel_delayed_work_sync(&priv->lec_arp_work);
}
lec_arp_init(priv);


More information

Oops-Analysis: http://oops.fenrus.org/reports/lkml/69f16c26.170a022...@google.com/
Assisted-by: GitHub-Copilot linux-kernel-oops.

Jakub Kicinski

unread,
Apr 29, 2026, 7:17:23 PM (13 hours ago) Apr 29
to Arjan van de Ven, net...@vger.kernel.org, syzbot+ca9d56...@syzkaller.appspotmail.com, da...@davemloft.net, edum...@google.com, ho...@kernel.org, linux-...@vger.kernel.org, pab...@redhat.com, syzkall...@googlegroups.com
On Wed, 29 Apr 2026 08:17:41 -0700 Arjan van de Ven wrote:
> This email is created by automation to help kernel developers deal with
> a large volume of bug reports by decoding oopses into more actionable
> information.

Just one opinion but I don't think it is helping me.
I'd assume at this point that maintainers can run the syzbot reports
thru their own slop generators if they want to?
And hopefully those local slop generators would notice obvious facts
like that this is a report for code which no longer exists upstream :\
Reply all
Reply to author
Forward
0 new messages