Oops. Forgot to add the target git tree for the patch. It is targeted for net- tree. On 5/16/2024 9:30 PM, Hou Tao wrote: > From: Hou Tao <houtao1@xxxxxxxxxx> > > The following slab-use-after-free problem was reported by syzbot: > > ================================================================== > BUG: KASAN: slab-use-after-free in lockdep_register_key+0x253/0x3f0 kernel/locking/lockdep.c:1225 > Read of size 8 at addr ffff88805fe2c298 by task syz-executor.1/5906 > > CPU: 1 PID: 5906 Comm: syz-executor.1 Not tainted 6.9.0-rc5-syzkaller-01473-g2506f6229bd0 #0 > ...... > Call Trace: > <TASK> > __dump_stack lib/dump_stack.c:88 [inline] > dump_stack_lvl+0x241/0x360 lib/dump_stack.c:114 > print_address_description mm/kasan/report.c:377 [inline] > print_report+0x169/0x550 mm/kasan/report.c:488 > kasan_report+0x143/0x180 mm/kasan/report.c:601 > lockdep_register_key+0x253/0x3f0 kernel/locking/lockdep.c:1225 > htab_map_alloc+0x9b/0xe60 kernel/bpf/hashtab.c:506 > map_create+0x90c/0x1200 kernel/bpf/syscall.c:1333 > __sys_bpf+0x6d1/0x810 kernel/bpf/syscall.c:5659 > do_syscall_x64 arch/x86/entry/common.c:52 [inline] > ...... > </TASK> > > Allocated by task 5593: > kasan_save_stack mm/kasan/common.c:47 [inline] > kasan_save_track+0x3f/0x80 mm/kasan/common.c:68 > poison_kmalloc_redzone mm/kasan/common.c:370 [inline] > __kasan_kmalloc+0x98/0xb0 mm/kasan/common.c:387 > kasan_kmalloc include/linux/kasan.h:211 [inline] > __do_kmalloc_node mm/slub.c:3966 [inline] > __kmalloc_node_track_caller+0x24e/0x4e0 mm/slub.c:3986 > kmalloc_reserve+0x111/0x2a0 net/core/skbuff.c:597 > __alloc_skb+0x1f3/0x440 net/core/skbuff.c:666 > alloc_skb include/linux/skbuff.h:1308 [inline] > alloc_skb_with_frags+0xc3/0x770 net/core/skbuff.c:6455 > ...... > > Freed by task 5593: > kasan_save_stack mm/kasan/common.c:47 [inline] > kasan_save_track+0x3f/0x80 mm/kasan/common.c:68 > kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:579 > poison_slab_object+0xa6/0xe0 mm/kasan/common.c:240 > __kasan_slab_free+0x37/0x60 mm/kasan/common.c:256 > kasan_slab_free include/linux/kasan.h:184 [inline] > slab_free_hook mm/slub.c:2106 [inline] > slab_free mm/slub.c:4280 [inline] > kfree+0x153/0x3a0 mm/slub.c:4390 > skb_kfree_head net/core/skbuff.c:1033 [inline] > skb_free_head net/core/skbuff.c:1045 [inline] > ...... > > The buggy address belongs to the object at ffff88805fe2c000 > which belongs to the cache kmalloc-2k of size 2048 > The buggy address is located 664 bytes inside of > freed 2048-byte region [ffff88805fe2c000, ffff88805fe2c800) > > At first glance, it seems there is a problem with bpf hash-table, > because the use-after-free problem is reported when invoking > htab_map_alloc(). However, after checking the reported error more > carefully, it appears that qdiscs_alloc() is the culprit. The most > important clue regarding why qdisc_alloc() is involved is the following: > "The buggy address is located 664 bytes inside of freed 2048-byte > region". lockdep_register_key() has several callers, and only the > offset of lock_class_key in Qdisc in 664. The problem occurs as follow: > > (1) call qdisc_alloc() > After calling lockdep_register_key(), qdisc_alloc() jumps to errout1 > label because netdev_alloc_pcpu_stats() or alloc_percpu() fails (e.g., > due to mem-cg limitation or SIGKILL). However it doesn't call > lockdep_unregister_key() to unregister root_lock_key, but it frees the > allocated memory. > > (2) call htab_map_alloc > During the calling of lockdep_register_key(), it finds the lockdep_key > registered by free-ed Qdisc and triggers the use-after-free. > > Fix it by invoking lockdep_unregister_key() in the error path of > qdisc_alloc(). > > Reported-by: syzbot+061f58eec3bde7ee8ffa@xxxxxxxxxxxxxxxxxxxxxxxxx > Closes: https://lore.kernel.org/bpf/d28e4f02-965d-96de-ee56-f7a001b67fe7@xxxxxxxxxxxxxxx/T/#m47c0670021ada17869bf887c73438133d879d326 > Fixes: af0cb3fa3f9e ("net/sched: fix false lockdep warning on qdisc root lock") > Signed-off-by: Hou Tao <houtao1@xxxxxxxxxx> > --- > net/sched/sch_generic.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c > index 31dfd6c7405b0..d3f6006b563cc 100644 > --- a/net/sched/sch_generic.c > +++ b/net/sched/sch_generic.c > @@ -982,6 +982,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, > > return sch; > errout1: > + lockdep_unregister_key(&sch->root_lock_key); > kfree(sch); > errout: > return ERR_PTR(err);