GangMin Kim
unread,Feb 22, 2026, 8:27:54 PM (15 hours ago) Feb 22Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to da...@davemloft.net, Eric Dumazet, Jamal Hadi Salim, Jiri Pirko, ku...@kernel.org, net...@vger.kernel.org, Paolo Abeni, ho...@kernel.org, linux-...@vger.kernel.org, syzk...@googlegroups.com
Dear Linux kernel developers and maintainers,
Using a modified version of syzkaller, I identified a new bug and
refined the PoC, and the bug-related information is attached
below.Please let me know if you need any further information.
Summary
A NULL Pointer Dereference occurs because there is no proper check for
whether cl is NULL when a class is found via cops->find() and then
used in cops->qlen_notify().
This description provides an explanation and KASAN report for
qfq_qlen_notify, but the vulnerability can occur in various other
places such as drr_qlen_notify, hfsc_qlen_notify, htb_qlen_notify,
etc.
Keywords
- net/sched
Kernel Info
Version: (Output of /proc/version)
- Linux version 7.0.0-rc1
Commit: (Git hash if applicable)
- 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
Description(Root Cause)
```c
void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
{
const struct Qdisc_class_ops *cops;
unsigned long cl;
u32 parentid;
bool notify;
int drops;
drops = max_t(int, n, 0);
rcu_read_lock();
while ((parentid = sch->parent)) {
if (parentid == TC_H_ROOT)
break;
if (sch->flags & TCQ_F_NOPARENT)
break;
/* Notify parent qdisc only if child qdisc becomes empty. */
notify = !sch->q.qlen;
/* TODO: perform the search on a per txq basis */
sch = qdisc_lookup_rcu(qdisc_dev(sch), TC_H_MAJ(parentid));
if (sch == NULL) {
WARN_ON_ONCE(parentid != TC_H_ROOT);
break;
}
cops = sch->ops->cl_ops;
if (notify && cops->qlen_notify) { // [1]
/* Note that qlen_notify must be idempotent as it may get called
* multiple times.
*/
cl = cops->find(sch, parentid); // [2]
cops->qlen_notify(sch, cl); // [3]
}
sch->q.qlen -= n;
sch->qstats.backlog -= len;
__qdisc_qstats_drop(sch, drops);
}
rcu_read_unlock();
}
```
When condition [1] is satisfied, cl is retrieved at [2] and then
passed to [3]. Here, [2] can return NULL, and using this value at [3]
can cause a NULL Pointer Dereference.
```c
static unsigned long qfq_search_class(struct Qdisc *sch, u32 classid)
{
return (unsigned long)qfq_find_class(sch, classid);
}
static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
{
struct qfq_sched *q = qdisc_priv(sch);
struct Qdisc_class_common *clc;
clc = qdisc_class_find(&q->clhash, classid);
if (clc == NULL)
return NULL; // [4]
return container_of(clc, struct qfq_class, common);
}
```
When QFQ is configured, the above function is executed at [2], and
NULL can be returned at [4].
```c
static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg)
{
struct qfq_sched *q = qdisc_priv(sch);
struct qfq_class *cl = (struct qfq_class *)arg; // [5]
if (list_empty(&cl->alist)) // [6]
return;
qfq_deactivate_class(q, cl);
}
```
If NULL is returned at [2], that value is passed directly to [3],
which becomes cl through [5]. Subsequently, a NULL Pointer Dereference
occurs at [6].
Kasan Report
Oops: general protection fault, probably for non-canonical address
0xdffffc000000000b: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000058-0x000000000000005f]
CPU: 0 UID: 0 PID: 377 Comm: test Not tainted 7.0.0-rc1 #54 PREEMPT(full)
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix,
1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:qfq_qlen_notify+0x2e/0x180 net/sched/sch_qfq.c:1434
Code: 41 57 41 56 41 55 41 54 55 48 89 fd 53 48 89 f3 4c 8d 7b 58 e8
e3 b3 8a fd 4c 89 fa 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 <80> 3c
02 00 0f 85 f8 00 00 00 48 8b 43 58 49 39 c7 0f 84 b9 00 00
RSP: 0018:ffff88811a447258 EFLAGS: 00010212
RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffffffff83e2af6d
RDX: 000000000000000b RSI: 0000000000000000 RDI: ffff88811b524000
RBP: ffff88811b524000 R08: 0000000000000000 R09: fffffbfff0d3595c
R10: ffffffff869acae7 R11: 00000000ac3123a9 R12: ffffffff859b0b60
R13: ffffffff859b0b40 R14: 0000000000000000 R15: 0000000000000058
FS: 00007ff24e5da700(0000) GS:ffff88834ad0d000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ff24e6e95f0 CR3: 000000011a5ff000 CR4: 0000000000750ef0
PKRU: 55555554
Call Trace:
<TASK>
__qdisc_qstats_drop include/net/sch_generic.h:958 [inline]
qdisc_tree_reduce_backlog+0x128/0x400 net/sched/sch_api.c:812
tbf_offload_graft net/sched/sch_tbf.c:191 [inline]
tbf_graft+0x1cc/0x590 net/sched/sch_tbf.c:573
qdisc_refcount_dec_if_one include/net/sch_generic.h:152 [inline]
qdisc_graft+0x2ef/0x1460 net/sched/sch_api.c:1117
__tc_modify_qdisc net/sched/sch_api.c:1631 [inline]
tc_modify_qdisc+0xf4f/0x1e40 net/sched/sch_api.c:1819
rcu_read_unlock include/linux/rcupdate.h:883 [inline]
rtnetlink_rcv_msg+0x3b9/0xa90 net/core/rtnetlink.c:6913
netlink_rcv_skb+0x12e/0x390 net/netlink/af_netlink.c:2539
kfree_skb_reason include/linux/skbuff.h:1322 [inline]
kfree_skb include/linux/skbuff.h:1331 [inline]
netlink_unicast_kernel net/netlink/af_netlink.c:1321 [inline]
netlink_unicast+0x6c1/0x970 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x79c/0xc50 net/netlink/af_netlink.c:2465
__sock_release net/socket.c:673 [inline]
____sys_sendmsg+0x8b2/0xa50 net/socket.c:690
sendmsg_copy_msghdr net/socket.c:2621 [inline]
___sys_sendmsg+0x120/0x1c0 net/socket.c:2642
__sys_sendmsg+0x147/0x1f0 net/socket.c:2681
arch_atomic64_read arch/x86/include/asm/atomic64_64.h:15 [inline]
raw_atomic64_read include/linux/atomic/atomic-arch-fallback.h:2583 [inline]
raw_atomic_long_read include/linux/atomic/atomic-long.h:38 [inline]
atomic_long_read include/linux/atomic/atomic-instrumented.h:3189 [inline]
unwind_reset_info include/linux/unwind_deferred.h:37 [inline]
exit_to_user_mode include/linux/irq-entry-common.h:296 [inline]
syscall_exit_to_user_mode include/linux/entry-common.h:327 [inline]
do_syscall_64+0xf1/0x530 arch/x86/entry/syscall_64.c:100
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff24e7c4e4d
Code: 28 89 54 24 1c 48 89 74 24 10 89 7c 24 08 e8 ca ee ff ff 8b 54
24 1c 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 2e 00 00 00 0f 05 <48> 3d
00 f0 ff ff 77 33 44 89 c7 48 89 44 24 08 e8 fe ee ff ff 48
RSP: 002b:00007ff24e5d9d90 EFLAGS: 00000293 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ff24e7c4e4d
RDX: 0000000000000000 RSI: 00007ff24e5d9dd0 RDI: 0000000000000003
RBP: 00007ff24e5d9e30 R08: 0000000000000000 R09: 0000000000050000
R10: 0000000000000000 R11: 0000000000000293 R12: 00007ffcdc50ddde
R13: 00007ffcdc50dddf R14: 00007ff24e5d9fc0 R15: 0000000000022000
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:qfq_qlen_notify+0x2e/0x180 net/sched/sch_qfq.c:1434
Code: 41 57 41 56 41 55 41 54 55 48 89 fd 53 48 89 f3 4c 8d 7b 58 e8
e3 b3 8a fd 4c 89 fa 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 <80> 3c
02 00 0f 85 f8 00 00 00 48 8b 43 58 49 39 c7 0f 84 b9 00 00
RSP: 0018:ffff88811a447258 EFLAGS: 00010212
RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffffffff83e2af6d
RDX: 000000000000000b RSI: 0000000000000000 RDI: ffff88811b524000
RBP: ffff88811b524000 R08: 0000000000000000 R09: fffffbfff0d3595c
R10: ffffffff869acae7 R11: 00000000ac3123a9 R12: ffffffff859b0b60
R13: ffffffff859b0b40 R14: 0000000000000000 R15: 0000000000000058
FS: 00007ff24e5da700(0000) GS:ffff88834ad0d000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ff24e6e95f0 CR3: 000000011a5ff000 CR4: 0000000000750ef0
PKRU: 55555554
----------------
Code disassembly (best guess):
0: 41 57 push %r15
2: 41 56 push %r14
4: 41 55 push %r13
6: 41 54 push %r12
8: 55 push %rbp
9: 48 89 fd mov %rdi,%rbp
c: 53 push %rbx
d: 48 89 f3 mov %rsi,%rbx
10: 4c 8d 7b 58 lea 0x58(%rbx),%r15
14: e8 e3 b3 8a fd call 0xfd8ab3fc
19: 4c 89 fa mov %r15,%rdx
1c: 48 b8 00 00 00 00 00 movabs $0xdffffc0000000000,%rax
23: fc ff df
26: 48 c1 ea 03 shr $0x3,%rdx
* 2a: 80 3c 02 00 cmpb $0x0,(%rdx,%rax,1) <-- trapping
instruction
2e: 0f 85 f8 00 00 00 jne 0x12c
34: 48 8b 43 58 mov 0x58(%rbx),%rax
38: 49 39 c7 cmp %rax,%r15
3b: 0f .byte 0xf
3c: 84 .byte 0x84
3d: b9 .byte 0xb9
R13: ffffffff859b0b40 R14: 0000000000000000 R15: 0000000000000058
FS: 00007ff24e5da700(0000) GS:ffff88834ad0d000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ff24e6e95f0 CR3: 000000011a5ff000 CR4: 0000000000750ef0
PKRU: 55555554
Kernel panic - not syncing: Fatal exception in interrupt
Kernel Offset: disabled
---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---