In the Linux kernel, the following vulnerability has been resolved:
net/sched: taprio: avoid disabling offload when it was never enabled
In an incredibly strange API design decision, qdisc->destroy() gets called even if qdisc->init() never succeeded, not exclusively since commit 87b60cfacf9f ("net_sched: fix error recovery at qdisc creation"), but apparently also earlier (in the case of qdisc_create_dflt()).
The taprio qdisc does not fully acknowledge this when it attempts full offload, because it starts off with q->flags = TAPRIO_FLAGS_INVALID in taprio_init(), then it replaces q->flags with TCA_TAPRIO_ATTR_FLAGS parsed from netlink (in taprio_change(), tail called from taprio_init()).
But in taprio_destroy(), we call taprio_disable_offload(), and this determines what to do based on FULL_OFFLOAD_IS_ENABLED(q->flags).
But looking at the implementation of FULL_OFFLOAD_IS_ENABLED() (a bitwise check of bit 1 in q->flags), it is invalid to call this macro on q->flags when it contains TAPRIO_FLAGS_INVALID, because that is set to U32_MAX, and therefore FULL_OFFLOAD_IS_ENABLED() will return true on an invalid set of flags.
As a result, it is possible to crash the kernel if user space forces an error between setting q->flags = TAPRIO_FLAGS_INVALID, and the calling of taprio_enable_offload(). This is because drivers do not expect the offload to be disabled when it was never enabled.
The error that we force here is to attach taprio as a non-root qdisc, but instead as child of an mqprio root qdisc:
$ tc qdisc add dev swp0 root handle 1: \ mqprio num_tc 8 map 0 1 2 3 4 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 hw 0 $ tc qdisc replace dev swp0 parent 1:1 \ taprio num_tc 8 map 0 1 2 3 4 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 0 \ sched-entry S 0x7f 990000 sched-entry S 0x80 100000 \ flags 0x0 clockid CLOCK_TAI Unable to handle kernel paging request at virtual address fffffffffffffff8 [fffffffffffffff8] pgd=0000000000000000, p4d=0000000000000000 Internal error: Oops: 96000004 [#1] PREEMPT SMP Call trace: taprio_dump+0x27c/0x310 vsc9959_port_setup_tc+0x1f4/0x460 felix_port_setup_tc+0x24/0x3c dsa_slave_setup_tc+0x54/0x27c taprio_disable_offload.isra.0+0x58/0xe0 taprio_destroy+0x80/0x104 qdisc_create+0x240/0x470 tc_modify_qdisc+0x1fc/0x6b0 rtnetlink_rcv_msg+0x12c/0x390 netlink_rcv_skb+0x5c/0x130 rtnetlink_rcv+0x1c/0x2c
Fix this by keeping track of the operations we made, and undo the offload only if we actually did it.
I've added "bool offloaded" inside a 4 byte hole between "int clockid" and "atomic64_t picos_per_byte". Now the first cache line looks like below:
$ pahole -C taprio_sched net/sched/sch_taprio.o struct taprio_sched { struct Qdisc * * qdiscs; /* 0 8 */ struct Qdisc * root; /* 8 8 */ u32 flags; /* 16 4 */ enum tk_offsets tk_offset; /* 20 4 */ int clockid; /* 24 4 */ bool offloaded; /* 28 1 */
/* XXX 3 bytes hole, try to pack */
atomic64_t picos_per_byte; /* 32 0 */
/* XXX 8 bytes hole, try to pack */
spinlock_t current_entry_lock; /* 40 0 */
/* XXX 8 bytes hole, try to pack */
struct sched_entry * current_entry; /* 48 8 */ struct sched_gate_list * oper_sched; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */
CVSS Details
- CVSS 3.1 Base Score: 5.5
- CVSS 3.1 Vector: (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H)
Covered by Rapid7
| Product | Vendor Advisory | Solution File | Added | Published |
|---|---|---|---|---|
| Amazon Linux Ami 2 | — | Upgrade kernel-tools-develUpgrade perfUpgrade python-perf-debuginfoUpgrade perf-debuginfoUpgrade kernel-livepatch-5.15.73-48.135Upgrade kernel-livepatch-5.10.147-133.644Upgrade kernel-debuginfo-common-aarch64Upgrade kernel-develUpgrade kernel-headersUpgrade kernelUpgrade bpftool-debuginfoUpgrade kernel-debuginfoUpgrade python-perfUpgrade kernel-tools-debuginfoUpgrade bpftoolUpgrade kernel-toolsUpgrade kernel-debuginfo-common-x86_64 | Aug 2, 2024 | Apr 28, 2024 |
| Debian | — | Upgrade linux | Jul 30, 2024 | Apr 28, 2024 |
| Redhat_linux | — | No solution exists | Jul 9, 2025 | Apr 28, 2024 |
| Suse | — | Upgrade kernel-default-base-rebuildUpgrade kernel-rtUpgrade dtb-lgUpgrade kernel-devel-azureUpgrade kernel-rt-extraUpgrade dtb-mediatekUpgrade dtb-apmUpgrade kernel-default-optionalUpgrade ocfs2-kmp-rtUpgrade kernel-rt-vdsoUpgrade kernel-source-azureUpgrade gfs2-kmp-azureUpgrade kselftests-kmp-64kbUpgrade dtb-caviumUpgrade dtb-qcomUpgrade kernel-rt-livepatchUpgrade kernel-obs-buildUpgrade cluster-md-kmp-rtUpgrade dtb-xilinxUpgrade gfs2-kmp-rtUpgrade kernel-obs-qaUpgrade kernel-azure-livepatch-develUpgrade kernel-default-extraUpgrade kernel-develUpgrade dtb-alteraUpgrade kernel-macrosUpgrade cluster-md-kmp-azureUpgrade dlm-kmp-64kbUpgrade kernel-rt_debug-develUpgrade kernel-devel-rtUpgrade kernel-zfcpdumpUpgrade kernel-default-vdsoUpgrade kernel-kvmsmall-develUpgrade ocfs2-kmp-defaultUpgrade kernel-kvmsmallUpgrade kernel-rt-develUpgrade kernel-sourceUpgrade kernel-debug-vdsoUpgrade kernel-azure-optionalUpgrade dtb-rockchipUpgrade kernel-azure-develUpgrade dtb-amlogicUpgrade kernel-syms-azureUpgrade reiserfs-kmp-azureUpgrade dtb-exynosUpgrade dtb-amazonUpgrade dtb-armUpgrade dlm-kmp-rtUpgrade kernel-rt-optionalUpgrade dtb-allwinnerUpgrade reiserfs-kmp-defaultUpgrade ocfs2-kmp-64kbUpgrade kernel-kvmsmall-livepatch-develUpgrade kernel-docs-htmlUpgrade kernel-azure-extraUpgrade gfs2-kmp-defaultUpgrade gfs2-kmp-64kbUpgrade kernel-default-baseUpgrade dtb-marvellUpgrade kernel-symsUpgrade kselftests-kmp-defaultUpgrade kernel-docsUpgrade kernel-debug-develUpgrade kernel-64kb-extraUpgrade kernel-default-livepatch-develUpgrade kselftests-kmp-azureUpgrade dtb-freescaleUpgrade kernel-debug-livepatch-develUpgrade kernel-rt-livepatch-develUpgrade kernel-rt_debug-vdsoUpgrade reiserfs-kmp-64kbUpgrade kernel-azure-vdsoUpgrade dtb-broadcomUpgrade dlm-kmp-azureUpgrade kernel-source-vanillaUpgrade kernel-syms-rtUpgrade dtb-sprdUpgrade dtb-hisiliconUpgrade kernel-defaultUpgrade dlm-kmp-defaultUpgrade cluster-md-kmp-64kbUpgrade cluster-md-kmp-defaultUpgrade ocfs2-kmp-azureUpgrade dtb-appleUpgrade dtb-renesasUpgrade kernel-default-develUpgrade kernel-debugUpgrade kernel-azureUpgrade kernel-64kb-livepatch-develUpgrade kernel-64kb-develUpgrade dtb-amdUpgrade kernel-default-livepatchUpgrade kernel-rt_debug-livepatch-develUpgrade reiserfs-kmp-rtUpgrade kernel-64kb-optionalUpgrade kernel-source-rtUpgrade kernel-kvmsmall-vdsoUpgrade kernel-64kbUpgrade kselftests-kmp-rtUpgrade kernel-rt_debugUpgrade dtb-socionextUpgrade dtb-nvidia | Aug 9, 2024 | Apr 28, 2024 |
| Ubuntu | — | Upgrade linux-hwe-5.4Upgrade linux-intel-iotg-5.15Upgrade linux-gcp-fipsUpgrade linux-gkeopUpgrade linux-azureUpgrade linux-gkeop-5.15Upgrade linux-azure-5.15Upgrade linux-ibmUpgrade linux-iotUpgrade linux-hwe-5.15Upgrade linux-gcp-5.15Upgrade linux-aws-fipsUpgrade linux-kvmUpgrade linux-gcp-5.4Upgrade linux-oracleUpgrade linux-azure-fdeUpgrade linux-intel-iotgUpgrade linux-nvidiaUpgrade linux-realtimeUpgrade linux-azure-5.4Upgrade linux-azure-fipsUpgrade linux-oracle-5.15Upgrade linuxUpgrade linux-aws-5.15Upgrade linux-lowlatency-hwe-5.15Upgrade linux-oracle-5.4Upgrade linux-awsUpgrade linux-gkeUpgrade linux-aws-5.4Upgrade linux-fipsUpgrade linux-riscv-5.15Upgrade linux-bluefieldUpgrade linux-lowlatencyUpgrade linux-gcpUpgrade linux-raspi-5.4Upgrade linux-raspiUpgrade linux-ibm-5.4 | Nov 19, 2024 | Apr 28, 2024 |
| Vmware Photon_os | — | Use 'tdnf update' to upgrade all packages to the latest version. | Jan 20, 2025 | Apr 28, 2024 |
Prioritise with Active Threat Intelligence
With curated Threat Intelligence, you can see which vulnerabilities truly put you at risk, prioritize what matters most, and act before attackers do.
Explore Intelligence Hub