* [PATCH] locking/lockdep: Invalidate stale class_cache entries for zapped classes
@ 2026-08-24 15:51 Eric Dumazet
2026-08-25 0:29 ` Hillf Danton
0 siblings, 1 reply; 7+ messages in thread
From: Eric Dumazet @ 2026-08-24 15:51 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long
Cc: linux-kernel, netdev, Eric Dumazet, syzbot+2d770620059281e225a4
syzbot reported a lockdep splat hitting DEBUG_LOCKS_WARN_ON(1) in
hlock_class() due to an invalid class_idx:
WARNING: kernel/locking/lockdep.c:238 at __lock_acquire+0x382/0x2cf0 kernel/locking/lockdep.c:5203
Workqueue: wg-crypt-wg0 wg_packet_tx_worker
RIP: 0010:hlock_class kernel/locking/lockdep.c:238 [inline]
RIP: 0010:check_wait_context kernel/locking/lockdep.c:4870 [inline]
RIP: 0010:__lock_acquire+0x389/0x2cf0 kernel/locking/lockdep.c:5203
Call Trace:
<IRQ>
lock_acquire+0x106/0x350 kernel/locking/lockdep.c:5886
_raw_spin_lock+0x2e/0x40 kernel/locking/spinlock.c:173
tcp_tsq_handler+0x29/0x200 net/ipv4/tcp_output.c:1291
tcp_tsq_workfn+0x384/0x410 net/ipv4/tcp_output.c:1325
...
When a lock class is zapped (e.g. during module unload or key
unregistration), zap_class() clears the class's bit in
lock_classes_in_use and removes it from the class hash table.
However, existing lockdep_map instances embedded in data structures
may still retain a pointer to the zapped class in their class_cache[]
array.
When __lock_acquire() subsequently runs on such a lock, it finds
lock->class_cache[subclass] != NULL, skipping register_lock_class() and
assigning hlock->class_idx to the index of the zapped class. When
check_wait_context() or hlock_class() inspects the held_lock, it finds
!test_bit(class_idx, lock_classes_in_use) and warns. Furthermore, if
the zapped slot is subsequently re-allocated to an unrelated lock key,
the stale class_cache entry would erroneously match the unrelated class
(ABA issue).
Add lock_class_cache_is_valid() to validate that the cached class is
within lock_classes bounds, still allocated in lock_classes_in_use
(using uninstrumented arch_test_bit() in __always_inline context so it
is safe in noinstr contexts like match_held_lock()), and that class->key
matches the expected subkey (taking lockdep_set_subclass() overrides into
account). Also use READ_ONCE()/WRITE_ONCE() when accessing class_cache[].
If the entry is invalid or stale, fall back to register_lock_class() /
look_up_lock_class().
Fixes: a0b0fd53e1e6 ("locking/lockdep: Free lock classes that are no longer in use")
Reported-by: syzbot+2d770620059281e225a4@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a8c66dc.4d75e56a.c9a88.0050.GAE@google.com/T/#u
Assisted-by: Gemini:gemini-3.1-pro
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
kernel/locking/lockdep.c | 50 +++++++++++++++++++++++++++++++++-------
1 file changed, 42 insertions(+), 8 deletions(-)
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 25d77d4a1061..763f79806bd8 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -963,6 +963,34 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
return NULL;
}
+static __always_inline bool lock_class_cache_is_valid(const struct lockdep_map *lock,
+ const struct lock_class *class,
+ unsigned int subclass)
+{
+ unsigned int class_subclass;
+
+ if (!class)
+ return false;
+
+ if (unlikely(class < lock_classes || class >= lock_classes + MAX_LOCKDEP_KEYS))
+ return false;
+
+ if (unlikely(!arch_test_bit(class - lock_classes, lock_classes_in_use)))
+ return false;
+
+ if (unlikely(!lock->key))
+ return false;
+
+ class_subclass = subclass ? subclass : class->subclass;
+ if (unlikely(class_subclass >= MAX_LOCKDEP_SUBCLASSES))
+ return false;
+
+ if (unlikely(READ_ONCE(class->key) != lock->key->subkeys + class_subclass))
+ return false;
+
+ return true;
+}
+
/*
* Static locks do not have their class-keys yet - for them the key is
* the lock object itself. If the lock is in the per cpu area, the
@@ -1395,9 +1423,9 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
out_set_class_cache:
if (!subclass || force)
- lock->class_cache[0] = class;
+ WRITE_ONCE(lock->class_cache[0], class);
else if (subclass < NR_LOCKDEP_CACHING_CLASSES)
- lock->class_cache[subclass] = class;
+ WRITE_ONCE(lock->class_cache[subclass], class);
/*
* Hash collision, did we smoke some? We found a class with a matching
@@ -4957,7 +4985,7 @@ void lockdep_init_map_type(struct lockdep_map *lock, const char *name,
int i;
for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
- lock->class_cache[i] = NULL;
+ WRITE_ONCE(lock->class_cache[i], NULL);
#ifdef CONFIG_LOCK_STAT
lock->cpu = raw_smp_processor_id();
@@ -5022,12 +5050,15 @@ EXPORT_SYMBOL_GPL(__lockdep_no_track__);
void lockdep_set_lock_cmp_fn(struct lockdep_map *lock, lock_cmp_fn cmp_fn,
lock_print_fn print_fn)
{
- struct lock_class *class = lock->class_cache[0];
+ struct lock_class *class = READ_ONCE(lock->class_cache[0]);
unsigned long flags;
raw_local_irq_save(flags);
lockdep_recursion_inc();
+ if (!lock_class_cache_is_valid(lock, class, 0))
+ class = NULL;
+
if (!class)
class = register_lock_class(lock, 0, 0);
@@ -5119,8 +5150,11 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
if (DEBUG_LOCKS_WARN_ON(subclass >= MAX_LOCKDEP_SUBCLASSES))
return 0;
- if (subclass < NR_LOCKDEP_CACHING_CLASSES)
- class = lock->class_cache[subclass];
+ if (subclass < NR_LOCKDEP_CACHING_CLASSES) {
+ class = READ_ONCE(lock->class_cache[subclass]);
+ if (!lock_class_cache_is_valid(lock, class, subclass))
+ class = NULL;
+ }
/*
* Not cached?
*/
@@ -5323,9 +5357,9 @@ static noinstr int match_held_lock(const struct held_lock *hlock,
return 1;
if (hlock->references) {
- const struct lock_class *class = lock->class_cache[0];
+ const struct lock_class *class = READ_ONCE(lock->class_cache[0]);
- if (!class)
+ if (!lock_class_cache_is_valid(lock, class, 0))
class = look_up_lock_class(lock, 0);
/*
base-commit: 0a0d1d55dad570724bf8c7ea83409639cfb4be9b
--
2.55.0.766.g2966f0265a-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] locking/lockdep: Invalidate stale class_cache entries for zapped classes
2026-08-24 15:51 [PATCH] locking/lockdep: Invalidate stale class_cache entries for zapped classes Eric Dumazet
@ 2026-08-25 0:29 ` Hillf Danton
2026-08-25 0:59 ` [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler syzbot
0 siblings, 1 reply; 7+ messages in thread
From: Hillf Danton @ 2026-08-25 0:29 UTC (permalink / raw)
To: syzbot+2d770620059281e225a4
Cc: Peter Zijlstra, Boqun Feng, linux-kernel, netdev, Eric Dumazet
#syz test
syzbot reported a lockdep splat hitting DEBUG_LOCKS_WARN_ON(1) in
hlock_class() due to an invalid class_idx:
WARNING: kernel/locking/lockdep.c:238 at __lock_acquire+0x382/0x2cf0 kernel/locking/lockdep.c:5203
Workqueue: wg-crypt-wg0 wg_packet_tx_worker
RIP: 0010:hlock_class kernel/locking/lockdep.c:238 [inline]
RIP: 0010:check_wait_context kernel/locking/lockdep.c:4870 [inline]
RIP: 0010:__lock_acquire+0x389/0x2cf0 kernel/locking/lockdep.c:5203
Call Trace:
<IRQ>
lock_acquire+0x106/0x350 kernel/locking/lockdep.c:5886
_raw_spin_lock+0x2e/0x40 kernel/locking/spinlock.c:173
tcp_tsq_handler+0x29/0x200 net/ipv4/tcp_output.c:1291
tcp_tsq_workfn+0x384/0x410 net/ipv4/tcp_output.c:1325
...
When a lock class is zapped (e.g. during module unload or key
unregistration), zap_class() clears the class's bit in
lock_classes_in_use and removes it from the class hash table.
However, existing lockdep_map instances embedded in data structures
may still retain a pointer to the zapped class in their class_cache[]
array.
When __lock_acquire() subsequently runs on such a lock, it finds
lock->class_cache[subclass] != NULL, skipping register_lock_class() and
assigning hlock->class_idx to the index of the zapped class. When
check_wait_context() or hlock_class() inspects the held_lock, it finds
!test_bit(class_idx, lock_classes_in_use) and warns. Furthermore, if
the zapped slot is subsequently re-allocated to an unrelated lock key,
the stale class_cache entry would erroneously match the unrelated class
(ABA issue).
Add lock_class_cache_is_valid() to validate that the cached class is
within lock_classes bounds, still allocated in lock_classes_in_use
(using uninstrumented arch_test_bit() in __always_inline context so it
is safe in noinstr contexts like match_held_lock()), and that class->key
matches the expected subkey (taking lockdep_set_subclass() overrides into
account). Also use READ_ONCE()/WRITE_ONCE() when accessing class_cache[].
If the entry is invalid or stale, fall back to register_lock_class() /
look_up_lock_class().
Fixes: a0b0fd53e1e6 ("locking/lockdep: Free lock classes that are no longer in use")
Reported-by: syzbot+2d770620059281e225a4@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a8c66dc.4d75e56a.c9a88.0050.GAE@google.com/T/#u
Assisted-by: Gemini:gemini-3.1-pro
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
kernel/locking/lockdep.c | 50 +++++++++++++++++++++++++++++++++-------
1 file changed, 42 insertions(+), 8 deletions(-)
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 25d77d4a1061..763f79806bd8 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -963,6 +963,34 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
return NULL;
}
+static __always_inline bool lock_class_cache_is_valid(const struct lockdep_map *lock,
+ const struct lock_class *class,
+ unsigned int subclass)
+{
+ unsigned int class_subclass;
+
+ if (!class)
+ return false;
+
+ if (unlikely(class < lock_classes || class >= lock_classes + MAX_LOCKDEP_KEYS))
+ return false;
+
+ if (unlikely(!arch_test_bit(class - lock_classes, lock_classes_in_use)))
+ return false;
+
+ if (unlikely(!lock->key))
+ return false;
+
+ class_subclass = subclass ? subclass : class->subclass;
+ if (unlikely(class_subclass >= MAX_LOCKDEP_SUBCLASSES))
+ return false;
+
+ if (unlikely(READ_ONCE(class->key) != lock->key->subkeys + class_subclass))
+ return false;
+
+ return true;
+}
+
/*
* Static locks do not have their class-keys yet - for them the key is
* the lock object itself. If the lock is in the per cpu area, the
@@ -1395,9 +1423,9 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
out_set_class_cache:
if (!subclass || force)
- lock->class_cache[0] = class;
+ WRITE_ONCE(lock->class_cache[0], class);
else if (subclass < NR_LOCKDEP_CACHING_CLASSES)
- lock->class_cache[subclass] = class;
+ WRITE_ONCE(lock->class_cache[subclass], class);
/*
* Hash collision, did we smoke some? We found a class with a matching
@@ -4957,7 +4985,7 @@ void lockdep_init_map_type(struct lockdep_map *lock, const char *name,
int i;
for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
- lock->class_cache[i] = NULL;
+ WRITE_ONCE(lock->class_cache[i], NULL);
#ifdef CONFIG_LOCK_STAT
lock->cpu = raw_smp_processor_id();
@@ -5022,12 +5050,15 @@ EXPORT_SYMBOL_GPL(__lockdep_no_track__);
void lockdep_set_lock_cmp_fn(struct lockdep_map *lock, lock_cmp_fn cmp_fn,
lock_print_fn print_fn)
{
- struct lock_class *class = lock->class_cache[0];
+ struct lock_class *class = READ_ONCE(lock->class_cache[0]);
unsigned long flags;
raw_local_irq_save(flags);
lockdep_recursion_inc();
+ if (!lock_class_cache_is_valid(lock, class, 0))
+ class = NULL;
+
if (!class)
class = register_lock_class(lock, 0, 0);
@@ -5119,8 +5150,11 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
if (DEBUG_LOCKS_WARN_ON(subclass >= MAX_LOCKDEP_SUBCLASSES))
return 0;
- if (subclass < NR_LOCKDEP_CACHING_CLASSES)
- class = lock->class_cache[subclass];
+ if (subclass < NR_LOCKDEP_CACHING_CLASSES) {
+ class = READ_ONCE(lock->class_cache[subclass]);
+ if (!lock_class_cache_is_valid(lock, class, subclass))
+ class = NULL;
+ }
/*
* Not cached?
*/
@@ -5323,9 +5357,9 @@ static noinstr int match_held_lock(const struct held_lock *hlock,
return 1;
if (hlock->references) {
- const struct lock_class *class = lock->class_cache[0];
+ const struct lock_class *class = READ_ONCE(lock->class_cache[0]);
- if (!class)
+ if (!lock_class_cache_is_valid(lock, class, 0))
class = look_up_lock_class(lock, 0);
/*
base-commit: 0a0d1d55dad570724bf8c7ea83409639cfb4be9b
--
2.55.0.766.g2966f0265a-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler
2026-08-25 0:29 ` Hillf Danton
@ 2026-08-25 0:59 ` syzbot
2026-08-25 1:25 ` Hillf Danton
2026-08-25 1:27 ` Eric Dumazet
0 siblings, 2 replies; 7+ messages in thread
From: syzbot @ 2026-08-25 0:59 UTC (permalink / raw)
To: boqun, edumazet, hdanton, linux-kernel, netdev, peterz, syzkaller-bugs
Hello,
syzbot has tested the proposed patch but the reproducer is still triggering an issue:
WARNING in tcp_tsq_handler
------------[ cut here ]------------
!lockdep_sock_is_held(sk) && debug_locks
WARNING: ./include/net/sock.h:1799 at sock_owned_by_me include/net/sock.h:1799 [inline], CPU#1: kworker/1:0/24
WARNING: ./include/net/sock.h:1799 at sock_owned_by_user include/net/sock.h:1812 [inline], CPU#1: kworker/1:0/24
WARNING: ./include/net/sock.h:1799 at tcp_tsq_handler+0x1a6/0x200 net/ipv4/tcp_output.c:1292, CPU#1: kworker/1:0/24
Modules linked in:
CPU: 1 UID: 0 PID: 24 Comm: kworker/1:0 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
Workqueue: wg-crypt-wg0 wg_packet_tx_worker
RIP: 0010:sock_owned_by_me include/net/sock.h:1799 [inline]
RIP: 0010:sock_owned_by_user include/net/sock.h:1812 [inline]
RIP: 0010:tcp_tsq_handler+0x1a6/0x200 net/ipv4/tcp_output.c:1292
Code: 30 96 96 01 e8 7b b3 7a f7 be 02 00 00 00 eb 0a e8 6f b3 7a f7 be 01 00 00 00 4c 89 ff e8 82 3e 8f fa eb d0 e8 5b b3 7a f7 90 <0f> 0b 90 e9 fd fe ff ff 44 89 f9 80 e1 07 80 c1 03 38 c1 0f 8c 07
RSP: 0018:ffffc90000a08bb0 EFLAGS: 00010246
RAX: ffffffff8a4c8ba5 RBX: ffff88802db742d0 RCX: ffff88801e6e5dc0
RDX: 8000000000000100 RSI: 0000000000000100 RDI: 0000000000000000
RBP: 0000000000000001 R08: 0000000000000100 R09: 0000000000000004
R10: dffffc0000000000 R11: fffff52000141164 R12: dffffc0000000000
R13: ffffc90000a08c20 R14: ffff88802db74100 R15: ffff88802db74100
FS: 0000000000000000(0000) GS:ffff888124df1000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00005635f5ecdbd8 CR3: 0000000072ba6000 CR4: 00000000003526f0
Call Trace:
<IRQ>
tcp_tsq_workfn+0x384/0x410 net/ipv4/tcp_output.c:1325
process_one_work kernel/workqueue.c:3387 [inline]
process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
bh_worker+0x451/0x870 kernel/workqueue.c:3773
tasklet_action+0xc/0x70 kernel/softirq.c:997
handle_softirqs+0x226/0x860 kernel/softirq.c:645
do_softirq+0x77/0xd0 kernel/softirq.c:546
</IRQ>
<TASK>
__local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473
wg_socket_send_skb_to_peer+0x16b/0x1d0 drivers/net/wireguard/socket.c:183
wg_packet_create_data_done drivers/net/wireguard/send.c:251 [inline]
wg_packet_tx_worker+0x1c8/0x7e0 drivers/net/wireguard/send.c:276
process_one_work kernel/workqueue.c:3387 [inline]
process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3551
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>
Tested on:
commit: 66498c75 Merge tag 'dmaengine-7.3-rc1' of git://git.ke..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=10adc979580000
kernel config: https://syzkaller.appspot.com/x/.config?x=e9ce1d694820ba2b
dashboard link: https://syzkaller.appspot.com/bug?extid=2d770620059281e225a4
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
patch: https://syzkaller.appspot.com/x/patch.diff?x=1497b549580000
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler
2026-08-25 0:59 ` [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler syzbot
@ 2026-08-25 1:25 ` Hillf Danton
2026-08-25 1:27 ` Eric Dumazet
1 sibling, 0 replies; 7+ messages in thread
From: Hillf Danton @ 2026-08-25 1:25 UTC (permalink / raw)
To: syzbot; +Cc: boqun, edumazet, linux-kernel, netdev, peterz, syzkaller-bugs
> Date: Mon, 24 Aug 2026 17:59:01 -0700 [thread overview]
> Hello,
>
> syzbot has tested the proposed patch but the reproducer is still triggering an issue:
> WARNING in tcp_tsq_handler
>
Fine, another case of HBC, half baked croissant, thanks to syzbot.
> ------------[ cut here ]------------
> !lockdep_sock_is_held(sk) && debug_locks
> WARNING: ./include/net/sock.h:1799 at sock_owned_by_me include/net/sock.h:1799 [inline], CPU#1: kworker/1:0/24
> WARNING: ./include/net/sock.h:1799 at sock_owned_by_user include/net/sock.h:1812 [inline], CPU#1: kworker/1:0/24
> WARNING: ./include/net/sock.h:1799 at tcp_tsq_handler+0x1a6/0x200 net/ipv4/tcp_output.c:1292, CPU#1: kworker/1:0/24
> Modules linked in:
> CPU: 1 UID: 0 PID: 24 Comm: kworker/1:0 Not tainted syzkaller #0 PREEMPT(full)
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
> Workqueue: wg-crypt-wg0 wg_packet_tx_worker
> RIP: 0010:sock_owned_by_me include/net/sock.h:1799 [inline]
> RIP: 0010:sock_owned_by_user include/net/sock.h:1812 [inline]
> RIP: 0010:tcp_tsq_handler+0x1a6/0x200 net/ipv4/tcp_output.c:1292
> Code: 30 96 96 01 e8 7b b3 7a f7 be 02 00 00 00 eb 0a e8 6f b3 7a f7 be 01 00 00 00 4c 89 ff e8 82 3e 8f fa eb d0 e8 5b b3 7a f7 90 <0f> 0b 90 e9 fd fe ff ff 44 89 f9 80 e1 07 80 c1 03 38 c1 0f 8c 07
> RSP: 0018:ffffc90000a08bb0 EFLAGS: 00010246
> RAX: ffffffff8a4c8ba5 RBX: ffff88802db742d0 RCX: ffff88801e6e5dc0
> RDX: 8000000000000100 RSI: 0000000000000100 RDI: 0000000000000000
> RBP: 0000000000000001 R08: 0000000000000100 R09: 0000000000000004
> R10: dffffc0000000000 R11: fffff52000141164 R12: dffffc0000000000
> R13: ffffc90000a08c20 R14: ffff88802db74100 R15: ffff88802db74100
> FS: 0000000000000000(0000) GS:ffff888124df1000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00005635f5ecdbd8 CR3: 0000000072ba6000 CR4: 00000000003526f0
> Call Trace:
> <IRQ>
> tcp_tsq_workfn+0x384/0x410 net/ipv4/tcp_output.c:1325
> process_one_work kernel/workqueue.c:3387 [inline]
> process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
> bh_worker+0x451/0x870 kernel/workqueue.c:3773
> tasklet_action+0xc/0x70 kernel/softirq.c:997
> handle_softirqs+0x226/0x860 kernel/softirq.c:645
> do_softirq+0x77/0xd0 kernel/softirq.c:546
> </IRQ>
> <TASK>
> __local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473
> wg_socket_send_skb_to_peer+0x16b/0x1d0 drivers/net/wireguard/socket.c:183
> wg_packet_create_data_done drivers/net/wireguard/send.c:251 [inline]
> wg_packet_tx_worker+0x1c8/0x7e0 drivers/net/wireguard/send.c:276
> process_one_work kernel/workqueue.c:3387 [inline]
> process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
> worker_thread+0xa47/0xfb0 kernel/workqueue.c:3551
> 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>
>
>
> Tested on:
>
> commit: 66498c75 Merge tag 'dmaengine-7.3-rc1' of git://git.ke..
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=10adc979580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=e9ce1d694820ba2b
> dashboard link: https://syzkaller.appspot.com/bug?extid=2d770620059281e225a4
> compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
> patch: https://syzkaller.appspot.com/x/patch.diff?x=1497b549580000
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler
2026-08-25 0:59 ` [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler syzbot
2026-08-25 1:25 ` Hillf Danton
@ 2026-08-25 1:27 ` Eric Dumazet
2026-08-25 1:50 ` Eric Dumazet
1 sibling, 1 reply; 7+ messages in thread
From: Eric Dumazet @ 2026-08-25 1:27 UTC (permalink / raw)
To: syzbot, Shin'ichiro Kawasaki, Nilay Shroff, Keith Busch
Cc: boqun, hdanton, linux-kernel, netdev, peterz, syzkaller-bugs
On Tue, Aug 25, 2026 at 2:59 AM syzbot
<syzbot+2d770620059281e225a4@syzkaller.appspotmail.com> wrote:
>
> Hello,
>
> syzbot has tested the proposed patch but the reproducer is still triggering an issue:
> WARNING in tcp_tsq_handler
>
> ------------[ cut here ]------------
> !lockdep_sock_is_held(sk) && debug_locks
> WARNING: ./include/net/sock.h:1799 at sock_owned_by_me include/net/sock.h:1799 [inline], CPU#1: kworker/1:0/24
> WARNING: ./include/net/sock.h:1799 at sock_owned_by_user include/net/sock.h:1812 [inline], CPU#1: kworker/1:0/24
> WARNING: ./include/net/sock.h:1799 at tcp_tsq_handler+0x1a6/0x200 net/ipv4/tcp_output.c:1292, CPU#1: kworker/1:0/24
Note this is a different warning.
This one might have been added in nvme-tcp in commit
commit 19bdb70c77d3b24239a453291299b64040bdba86
Author: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Date: Thu Jun 4 11:32:08 2026 +0900
nvme-tcp: lockdep: use dynamic lockdep keys per socket instance
The authors assumed that __fput_sync(queue->sock->file) in
nvme_tcp_free_queue() synchronously destroys the socket, so they
unregistered the keys immediately:
__fput_sync(queue->sock->file);
queue->sock = NULL;
...
#ifdef CONFIG_DEBUG_LOCK_ALLOC
lockdep_unregister_key(&queue->nvme_tcp_sk_key);
lockdep_unregister_key(&queue->nvme_tcp_slock_key);
#endif
However, a TCP socket's lifetime is asynchronous:
in-flight skbs (e.g. buffered in a qdisc or device ring) hold
references on sk->sk_wmem_alloc.
When those packets are freed later, tcp_wfree() puts sk on TSQ and
tcp_tsq_handler(sk)
acquires bh_lock_sock(sk) on a socket whose lockdep key has already
been unregistered and zapped.
All other kernel storage/networking clients (sunrpc, nbd, cifs,
iscsi_tcp, rxe, siw) use static lockdep keys without issue.
> Modules linked in:
> CPU: 1 UID: 0 PID: 24 Comm: kworker/1:0 Not tainted syzkaller #0 PREEMPT(full)
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
> Workqueue: wg-crypt-wg0 wg_packet_tx_worker
> RIP: 0010:sock_owned_by_me include/net/sock.h:1799 [inline]
> RIP: 0010:sock_owned_by_user include/net/sock.h:1812 [inline]
> RIP: 0010:tcp_tsq_handler+0x1a6/0x200 net/ipv4/tcp_output.c:1292
> Code: 30 96 96 01 e8 7b b3 7a f7 be 02 00 00 00 eb 0a e8 6f b3 7a f7 be 01 00 00 00 4c 89 ff e8 82 3e 8f fa eb d0 e8 5b b3 7a f7 90 <0f> 0b 90 e9 fd fe ff ff 44 89 f9 80 e1 07 80 c1 03 38 c1 0f 8c 07
> RSP: 0018:ffffc90000a08bb0 EFLAGS: 00010246
> RAX: ffffffff8a4c8ba5 RBX: ffff88802db742d0 RCX: ffff88801e6e5dc0
> RDX: 8000000000000100 RSI: 0000000000000100 RDI: 0000000000000000
> RBP: 0000000000000001 R08: 0000000000000100 R09: 0000000000000004
> R10: dffffc0000000000 R11: fffff52000141164 R12: dffffc0000000000
> R13: ffffc90000a08c20 R14: ffff88802db74100 R15: ffff88802db74100
> FS: 0000000000000000(0000) GS:ffff888124df1000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00005635f5ecdbd8 CR3: 0000000072ba6000 CR4: 00000000003526f0
> Call Trace:
> <IRQ>
> tcp_tsq_workfn+0x384/0x410 net/ipv4/tcp_output.c:1325
> process_one_work kernel/workqueue.c:3387 [inline]
> process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
> bh_worker+0x451/0x870 kernel/workqueue.c:3773
> tasklet_action+0xc/0x70 kernel/softirq.c:997
> handle_softirqs+0x226/0x860 kernel/softirq.c:645
> do_softirq+0x77/0xd0 kernel/softirq.c:546
> </IRQ>
> <TASK>
> __local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473
> wg_socket_send_skb_to_peer+0x16b/0x1d0 drivers/net/wireguard/socket.c:183
> wg_packet_create_data_done drivers/net/wireguard/send.c:251 [inline]
> wg_packet_tx_worker+0x1c8/0x7e0 drivers/net/wireguard/send.c:276
> process_one_work kernel/workqueue.c:3387 [inline]
> process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
> worker_thread+0xa47/0xfb0 kernel/workqueue.c:3551
> 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>
>
>
> Tested on:
>
> commit: 66498c75 Merge tag 'dmaengine-7.3-rc1' of git://git.ke..
> git tree: upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=10adc979580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=e9ce1d694820ba2b
> dashboard link: https://syzkaller.appspot.com/bug?extid=2d770620059281e225a4
> compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
> patch: https://syzkaller.appspot.com/x/patch.diff?x=1497b549580000
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler
2026-08-25 1:27 ` Eric Dumazet
@ 2026-08-25 1:50 ` Eric Dumazet
0 siblings, 0 replies; 7+ messages in thread
From: Eric Dumazet @ 2026-08-25 1:50 UTC (permalink / raw)
To: syzbot, Shin'ichiro Kawasaki, Nilay Shroff, Keith Busch
Cc: boqun, hdanton, linux-kernel, netdev, peterz, syzkaller-bugs
On Tue, Aug 25, 2026 at 3:27 AM Eric Dumazet <edumazet@google.com> wrote:
>
> On Tue, Aug 25, 2026 at 2:59 AM syzbot
> <syzbot+2d770620059281e225a4@syzkaller.appspotmail.com> wrote:
> >
> > Hello,
> >
> > syzbot has tested the proposed patch but the reproducer is still triggering an issue:
> > WARNING in tcp_tsq_handler
> >
> > ------------[ cut here ]------------
> > !lockdep_sock_is_held(sk) && debug_locks
> > WARNING: ./include/net/sock.h:1799 at sock_owned_by_me include/net/sock.h:1799 [inline], CPU#1: kworker/1:0/24
> > WARNING: ./include/net/sock.h:1799 at sock_owned_by_user include/net/sock.h:1812 [inline], CPU#1: kworker/1:0/24
> > WARNING: ./include/net/sock.h:1799 at tcp_tsq_handler+0x1a6/0x200 net/ipv4/tcp_output.c:1292, CPU#1: kworker/1:0/24
>
> Note this is a different warning.
>
> This one might have been added in nvme-tcp in commit
>
> commit 19bdb70c77d3b24239a453291299b64040bdba86
> Author: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
> Date: Thu Jun 4 11:32:08 2026 +0900
>
> nvme-tcp: lockdep: use dynamic lockdep keys per socket instance
>
> The authors assumed that __fput_sync(queue->sock->file) in
> nvme_tcp_free_queue() synchronously destroys the socket, so they
> unregistered the keys immediately:
>
> __fput_sync(queue->sock->file);
> queue->sock = NULL;
> ...
> #ifdef CONFIG_DEBUG_LOCK_ALLOC
> lockdep_unregister_key(&queue->nvme_tcp_sk_key);
> lockdep_unregister_key(&queue->nvme_tcp_slock_key);
> #endif
>
> However, a TCP socket's lifetime is asynchronous:
> in-flight skbs (e.g. buffered in a qdisc or device ring) hold
> references on sk->sk_wmem_alloc.
>
> When those packets are freed later, tcp_wfree() puts sk on TSQ and
> tcp_tsq_handler(sk)
> acquires bh_lock_sock(sk) on a socket whose lockdep key has already
> been unregistered and zapped.
>
> All other kernel storage/networking clients (sunrpc, nbd, cifs,
> iscsi_tcp, rxe, siw) use static lockdep keys without issue.
>
I think 19bdb70c77d3 should be reverted.
We can change TCP to use sk_gfp_mask(sk, GFP_ATOMIC) instead of
gfp_any() in tcp_disconnect()
This ensures tcp_disconnect() respects sk->sk_allocation = GFP_ATOMIC
and never acquires fs_reclaim under sk_lock.
WDYT?
^ permalink raw reply [flat|nested] 7+ messages in thread
* [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler
@ 2026-08-24 15:44 syzbot
0 siblings, 0 replies; 7+ messages in thread
From: syzbot @ 2026-08-24 15:44 UTC (permalink / raw)
To: davem, edumazet, horms, kuba, kuniyu, linux-kernel, ncardwell,
netdev, pabeni, syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: 388b607d107c Merge tag 'efi-next-for-v7.3' of git://git.ke..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=10f98979580000
kernel config: https://syzkaller.appspot.com/x/.config?x=335632b21d0ce540
dashboard link: https://syzkaller.appspot.com/bug?extid=2d770620059281e225a4
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=133c3549580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/20c420e92df0/disk-388b607d.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/82f836a86dcc/vmlinux-388b607d.xz
kernel image: https://storage.googleapis.com/syzbot-assets/c3b00ac47be8/bzImage-388b607d.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+2d770620059281e225a4@syzkaller.appspotmail.com
------------[ cut here ]------------
DEBUG_LOCKS_WARN_ON(1)
WARNING: kernel/locking/lockdep.c:238 at hlock_class kernel/locking/lockdep.c:238 [inline], CPU#1: kworker/1:0/24
WARNING: kernel/locking/lockdep.c:238 at check_wait_context kernel/locking/lockdep.c:4870 [inline], CPU#1: kworker/1:0/24
WARNING: kernel/locking/lockdep.c:238 at __lock_acquire+0x382/0x2cf0 kernel/locking/lockdep.c:5203, CPU#1: kworker/1:0/24
Modules linked in:
CPU: 1 UID: 0 PID: 24 Comm: kworker/1:0 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
Workqueue: wg-crypt-wg0 wg_packet_tx_worker
RIP: 0010:hlock_class kernel/locking/lockdep.c:238 [inline]
RIP: 0010:check_wait_context kernel/locking/lockdep.c:4870 [inline]
RIP: 0010:__lock_acquire+0x389/0x2cf0 kernel/locking/lockdep.c:5203
Code: 83 3d fa 48 f9 18 00 75 27 90 e8 b2 88 35 03 85 c0 74 1c 83 3d eb 3f d7 0e 00 75 13 48 8d 3d 1e 43 da 0e 48 c7 c6 8f 4c 59 8e <67> 48 0f b9 3a 90 31 c0 0f b6 98 c4 00 00 00 41 8b 45 20 25 ff 1f
RSP: 0018:ffffc90000a089b8 EFLAGS: 00010046
RAX: 0000000000000001 RBX: 0000000000042000 RCX: ffff88801eaaddc0
RDX: 8000000000000100 RSI: ffffffff8e594c8f RDI: ffffffff907cef80
RBP: 0000000000000001 R08: 0000000000000100 R09: 1ffffffff20f3d88
R10: dffffc0000000000 R11: fffffbfff20f3d89 R12: 0000000000000949
R13: ffff88801eaaea08 R14: ffff88801eaaddc0 R15: ffff88801eaae968
FS: 0000000000000000(0000) GS:ffff888124df4000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f390df782c0 CR3: 000000007747a000 CR4: 00000000003526f0
Call Trace:
<IRQ>
lock_acquire+0x106/0x350 kernel/locking/lockdep.c:5886
__raw_spin_lock include/linux/spinlock_api_smp.h:190 [inline]
_raw_spin_lock+0x2e/0x40 kernel/locking/spinlock.c:173
spin_lock include/linux/spinlock.h:347 [inline]
tcp_tsq_handler+0x29/0x200 net/ipv4/tcp_output.c:1291
tcp_tsq_workfn+0x384/0x410 net/ipv4/tcp_output.c:1325
process_one_work kernel/workqueue.c:3387 [inline]
process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
bh_worker+0x451/0x870 kernel/workqueue.c:3773
tasklet_action+0xc/0x70 kernel/softirq.c:997
handle_softirqs+0x226/0x860 kernel/softirq.c:645
do_softirq+0x77/0xd0 kernel/softirq.c:546
</IRQ>
<TASK>
__local_bh_enable_ip+0x100/0x140 kernel/softirq.c:473
wg_socket_send_skb_to_peer+0x16b/0x1d0 drivers/net/wireguard/socket.c:183
wg_packet_create_data_done drivers/net/wireguard/send.c:251 [inline]
wg_packet_tx_worker+0x1c8/0x7e0 drivers/net/wireguard/send.c:276
process_one_work kernel/workqueue.c:3387 [inline]
process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3551
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: 83 3d fa 48 f9 18 00 cmpl $0x0,0x18f948fa(%rip) # 0x18f94901
7: 75 27 jne 0x30
9: 90 nop
a: e8 b2 88 35 03 call 0x33588c1
f: 85 c0 test %eax,%eax
11: 74 1c je 0x2f
13: 83 3d eb 3f d7 0e 00 cmpl $0x0,0xed73feb(%rip) # 0xed74005
1a: 75 13 jne 0x2f
1c: 48 8d 3d 1e 43 da 0e lea 0xeda431e(%rip),%rdi # 0xeda4341
23: 48 c7 c6 8f 4c 59 8e mov $0xffffffff8e594c8f,%rsi
* 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
2f: 90 nop
30: 31 c0 xor %eax,%eax
32: 0f b6 98 c4 00 00 00 movzbl 0xc4(%rax),%ebx
39: 41 8b 45 20 mov 0x20(%r13),%eax
3d: 25 .byte 0x25
3e: ff 1f lcall *(%rdi)
---
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 syzkaller@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
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-25 1:50 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-24 15:51 [PATCH] locking/lockdep: Invalidate stale class_cache entries for zapped classes Eric Dumazet
2026-08-25 0:29 ` Hillf Danton
2026-08-25 0:59 ` [syzbot] [net?] WARNING: locking bug in tcp_tsq_handler syzbot
2026-08-25 1:25 ` Hillf Danton
2026-08-25 1:27 ` Eric Dumazet
2026-08-25 1:50 ` Eric Dumazet
-- strict thread matches above, loose matches on Subject: below --
2026-08-24 15:44 syzbot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®