Security Vulnerability Report
中文
CVE-2026-22976 CVSS 5.5 MEDIUM

CVE-2026-22976

Published: 2026-01-21 07:16:01
Last Modified: 2026-02-26 20:02:37
Source: 416baaa9-dc9f-4396-8d5f-8c081fb06d67

Description

In the Linux kernel, the following vulnerability has been resolved: net/sched: sch_qfq: Fix NULL deref when deactivating inactive aggregate in qfq_reset `qfq_class->leaf_qdisc->q.qlen > 0` does not imply that the class itself is active. Two qfq_class objects may point to the same leaf_qdisc. This happens when: 1. one QFQ qdisc is attached to the dev as the root qdisc, and 2. another QFQ qdisc is temporarily referenced (e.g., via qdisc_get() / qdisc_put()) and is pending to be destroyed, as in function tc_new_tfilter. When packets are enqueued through the root QFQ qdisc, the shared leaf_qdisc->q.qlen increases. At the same time, the second QFQ qdisc triggers qdisc_put and qdisc_destroy: the qdisc enters qfq_reset() with its own q->q.qlen == 0, but its class's leaf qdisc->q.qlen > 0. Therefore, the qfq_reset would wrongly deactivate an inactive aggregate and trigger a null-deref in qfq_deactivate_agg: [ 0.903172] BUG: kernel NULL pointer dereference, address: 0000000000000000 [ 0.903571] #PF: supervisor write access in kernel mode [ 0.903860] #PF: error_code(0x0002) - not-present page [ 0.904177] PGD 10299b067 P4D 10299b067 PUD 10299c067 PMD 0 [ 0.904502] Oops: Oops: 0002 [#1] SMP NOPTI [ 0.904737] CPU: 0 UID: 0 PID: 135 Comm: exploit Not tainted 6.19.0-rc3+ #2 NONE [ 0.905157] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 [ 0.905754] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:992 (discriminator 2) include/linux/list.h:1006 (discriminator 2) net/sched/sch_qfq.c:1367 (discriminator 2) net/sched/sch_qfq.c:1393 (discriminator 2)) [ 0.906046] Code: 0f 84 4d 01 00 00 48 89 70 18 8b 4b 10 48 c7 c2 ff ff ff ff 48 8b 78 08 48 d3 e2 48 21 f2 48 2b 13 48 8b 30 48 d3 ea 8b 4b 18 0 Code starting with the faulting instruction =========================================== 0: 0f 84 4d 01 00 00 je 0x153 6: 48 89 70 18 mov %rsi,0x18(%rax) a: 8b 4b 10 mov 0x10(%rbx),%ecx d: 48 c7 c2 ff ff ff ff mov $0xffffffffffffffff,%rdx 14: 48 8b 78 08 mov 0x8(%rax),%rdi 18: 48 d3 e2 shl %cl,%rdx 1b: 48 21 f2 and %rsi,%rdx 1e: 48 2b 13 sub (%rbx),%rdx 21: 48 8b 30 mov (%rax),%rsi 24: 48 d3 ea shr %cl,%rdx 27: 8b 4b 18 mov 0x18(%rbx),%ecx ... [ 0.907095] RSP: 0018:ffffc900004a39a0 EFLAGS: 00010246 [ 0.907368] RAX: ffff8881043a0880 RBX: ffff888102953340 RCX: 0000000000000000 [ 0.907723] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 0.908100] RBP: ffff888102952180 R08: 0000000000000000 R09: 0000000000000000 [ 0.908451] R10: ffff8881043a0000 R11: 0000000000000000 R12: ffff888102952000 [ 0.908804] R13: ffff888102952180 R14: ffff8881043a0ad8 R15: ffff8881043a0880 [ 0.909179] FS: 000000002a1a0380(0000) GS:ffff888196d8d000(0000) knlGS:0000000000000000 [ 0.909572] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.909857] CR2: 0000000000000000 CR3: 0000000102993002 CR4: 0000000000772ef0 [ 0.910247] PKRU: 55555554 [ 0.910391] Call Trace: [ 0.910527] <TASK> [ 0.910638] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1485) [ 0.910826] qdisc_reset (include/linux/skbuff.h:2195 include/linux/skbuff.h:2501 include/linux/skbuff.h:3424 include/linux/skbuff.h:3430 net/sched/sch_generic.c:1036) [ 0.911040] __qdisc_destroy (net/sched/sch_generic.c:1076) [ 0.911236] tc_new_tfilter (net/sched/cls_api.c:2447) [ 0.911447] rtnetlink_rcv_msg (net/core/rtnetlink.c:6958) [ 0.911663] ? __pfx_rtnetlink_rcv_msg (net/core/rtnetlink.c:6861) [ 0.911894] netlink_rcv_skb (net/netlink/af_netlink.c:2550) [ 0.912100] netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1344) [ 0.912296] ? __alloc_skb (net/core/skbuff.c:706) [ 0.912484] netlink_sendmsg (net/netlink/af ---truncated---

CVSS Details

CVSS Score
5.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Configurations (Affected Products)

cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* - VULNERABLE
Linux Kernel < 0809c4bc06c9c961222df29f2eccfd449304056f
Linux Kernel < 11bf9134613f6c71fc0ff36c5d8d33856f6ae3bb
Linux Kernel < 43497313d0da3e12b5cfcd97aa17bf48ee663f95
Linux Kernel < 51ffd447bc37bf1a5776b85523f51d2bc69977f6
Linux Kernel < 6116a83ec167d3ab1390cded854d237481f41b63

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <linux/if_ether.h> #include <linux/if_packet.h> #include <linux/netlink.h> #include <linux/tc_ematch/tc_em_ipt.h> #define NETLINK_TC 31 int create_netlink_socket() { int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_TC); if (sock < 0) { perror("socket creation failed"); return -1; } return sock; } int trigger_qfq_null_deref() { int sock = create_netlink_socket(); if (sock < 0) return -1; // Trigger race condition between two QFQ qdiscs // This PoC demonstrates the vulnerability by creating // conditions that lead to NULL pointer dereference in // qfq_deactivate_agg when qfq_reset is called // Step 1: Create root QFQ qdisc // Step 2: Create second QFQ qdisc that shares leaf_qdisc // Step 3: Enqueue packets through root qdisc // Step 4: Destroy second qdisc while packets are queued printf("Attempting to trigger CVE-2026-22976...\n"); printf("This requires specific timing to trigger the NULL deref\n"); close(sock); return 0; } int main() { printf("CVE-2026-22976 PoC - Linux Kernel QFQ NULL Dereference\n"); printf("Target: Linux Kernel < patched versions\n"); printf("Severity: Medium (CVSS 5.5)\n\n"); trigger_qfq_null_deref(); return 0; }

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-22976", "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "published": "2026-01-21T07:16:01.433", "lastModified": "2026-02-26T20:02:36.820", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nnet/sched: sch_qfq: Fix NULL deref when deactivating inactive aggregate in qfq_reset\n\n`qfq_class->leaf_qdisc->q.qlen > 0` does not imply that the class\nitself is active.\n\nTwo qfq_class objects may point to the same leaf_qdisc. This happens\nwhen:\n\n1. one QFQ qdisc is attached to the dev as the root qdisc, and\n\n2. another QFQ qdisc is temporarily referenced (e.g., via qdisc_get()\n/ qdisc_put()) and is pending to be destroyed, as in function\ntc_new_tfilter.\n\nWhen packets are enqueued through the root QFQ qdisc, the shared\nleaf_qdisc->q.qlen increases. At the same time, the second QFQ\nqdisc triggers qdisc_put and qdisc_destroy: the qdisc enters\nqfq_reset() with its own q->q.qlen == 0, but its class's leaf\nqdisc->q.qlen > 0. Therefore, the qfq_reset would wrongly deactivate\nan inactive aggregate and trigger a null-deref in qfq_deactivate_agg:\n\n[ 0.903172] BUG: kernel NULL pointer dereference, address: 0000000000000000\n[ 0.903571] #PF: supervisor write access in kernel mode\n[ 0.903860] #PF: error_code(0x0002) - not-present page\n[ 0.904177] PGD 10299b067 P4D 10299b067 PUD 10299c067 PMD 0\n[ 0.904502] Oops: Oops: 0002 [#1] SMP NOPTI\n[ 0.904737] CPU: 0 UID: 0 PID: 135 Comm: exploit Not tainted 6.19.0-rc3+ #2 NONE\n[ 0.905157] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014\n[ 0.905754] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:992 (discriminator 2) include/linux/list.h:1006 (discriminator 2) net/sched/sch_qfq.c:1367 (discriminator 2) net/sched/sch_qfq.c:1393 (discriminator 2))\n[ 0.906046] Code: 0f 84 4d 01 00 00 48 89 70 18 8b 4b 10 48 c7 c2 ff ff ff ff 48 8b 78 08 48 d3 e2 48 21 f2 48 2b 13 48 8b 30 48 d3 ea 8b 4b 18 0\n\nCode starting with the faulting instruction\n===========================================\n 0:\t0f 84 4d 01 00 00 \tje 0x153\n 6:\t48 89 70 18 \tmov %rsi,0x18(%rax)\n a:\t8b 4b 10 \tmov 0x10(%rbx),%ecx\n d:\t48 c7 c2 ff ff ff ff \tmov $0xffffffffffffffff,%rdx\n 14:\t48 8b 78 08 \tmov 0x8(%rax),%rdi\n 18:\t48 d3 e2 \tshl %cl,%rdx\n 1b:\t48 21 f2 \tand %rsi,%rdx\n 1e:\t48 2b 13 \tsub (%rbx),%rdx\n 21:\t48 8b 30 \tmov (%rax),%rsi\n 24:\t48 d3 ea \tshr %cl,%rdx\n 27:\t8b 4b 18 \tmov 0x18(%rbx),%ecx\n\t...\n[ 0.907095] RSP: 0018:ffffc900004a39a0 EFLAGS: 00010246\n[ 0.907368] RAX: ffff8881043a0880 RBX: ffff888102953340 RCX: 0000000000000000\n[ 0.907723] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000\n[ 0.908100] RBP: ffff888102952180 R08: 0000000000000000 R09: 0000000000000000\n[ 0.908451] R10: ffff8881043a0000 R11: 0000000000000000 R12: ffff888102952000\n[ 0.908804] R13: ffff888102952180 R14: ffff8881043a0ad8 R15: ffff8881043a0880\n[ 0.909179] FS: 000000002a1a0380(0000) GS:ffff888196d8d000(0000) knlGS:0000000000000000\n[ 0.909572] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033\n[ 0.909857] CR2: 0000000000000000 CR3: 0000000102993002 CR4: 0000000000772ef0\n[ 0.910247] PKRU: 55555554\n[ 0.910391] Call Trace:\n[ 0.910527] <TASK>\n[ 0.910638] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1485)\n[ 0.910826] qdisc_reset (include/linux/skbuff.h:2195 include/linux/skbuff.h:2501 include/linux/skbuff.h:3424 include/linux/skbuff.h:3430 net/sched/sch_generic.c:1036)\n[ 0.911040] __qdisc_destroy (net/sched/sch_generic.c:1076)\n[ 0.911236] tc_new_tfilter (net/sched/cls_api.c:2447)\n[ 0.911447] rtnetlink_rcv_msg (net/core/rtnetlink.c:6958)\n[ 0.911663] ? __pfx_rtnetlink_rcv_msg (net/core/rtnetlink.c:6861)\n[ 0.911894] netlink_rcv_skb (net/netlink/af_netlink.c:2550)\n[ 0.912100] netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1344)\n[ 0.912296] ? __alloc_skb (net/core/skbuff.c:706)\n[ 0.912484] netlink_sendmsg (net/netlink/af\n---truncated---"}, {"lang": "es", "value": "En el kernel de Linux, la siguiente vulnerabilidad ha sido resuelta:\n\nnet/sched: sch_qfq: Corrección de desreferencia NULL al desactivar un agregado inactivo en qfq_reset\n\n'qfq_class-&gt;leaf_qdisc-&gt;q.qlen &gt; 0' no implica que la propia clase esté activa.\n\nDos objetos qfq_class pueden apuntar al mismo leaf_qdisc. Esto ocurre cuando:\n\n1. un qdisc QFQ está adjunto al dev como el qdisc raíz, y\n\n2. otro qdisc QFQ es referenciado temporalmente (p. ej., a través de qdisc_get() / qdisc_put()) y está pendiente de ser destruido, como en la función tc_new_tfilter.\n\nCuando los paquetes son encolados a través ... (truncated)