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 kernelUpgrade kernel-tools-debuginfoUpgrade bpftoolUpgrade kernel-toolsUpgrade kernel-debuginfoUpgrade python-perfUpgrade kernel-debuginfo-common-x86_64Upgrade bpftool-debuginfoUpgrade perfUpgrade kernel-headersUpgrade python-perf-debuginfoUpgrade kernel-livepatch-5.15.73-48.135Upgrade perf-debuginfoUpgrade kernel-livepatch-5.10.147-133.644Upgrade kernel-develUpgrade kernel-tools-develUpgrade kernel-debuginfo-common-aarch64 | 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-kvmsmall-vdsoUpgrade kernel-64kb-optionalUpgrade kernel-syms-rtUpgrade kernel-64kb-develUpgrade reiserfs-kmp-rtUpgrade dlm-kmp-azureUpgrade dtb-broadcomUpgrade dtb-hisiliconUpgrade cluster-md-kmp-defaultUpgrade kernel-source-vanillaUpgrade cluster-md-kmp-64kbUpgrade dlm-kmp-defaultUpgrade kernel-debug-develUpgrade dtb-freescaleUpgrade ocfs2-kmp-azureUpgrade dtb-appleUpgrade kselftests-kmp-rtUpgrade dtb-nvidiaUpgrade kernel-default-livepatch-develUpgrade dtb-socionextUpgrade dlm-kmp-rtUpgrade kernel-symsUpgrade dtb-amazonUpgrade kernel-rt-optionalUpgrade kernel-debug-livepatch-develUpgrade kselftests-kmp-azureUpgrade dtb-sprdUpgrade kernel-rt-livepatch-develUpgrade kernel-default-livepatchUpgrade kernel-64kb-extraUpgrade kernel-rt_debugUpgrade dtb-renesasUpgrade kselftests-kmp-defaultUpgrade kernel-rt_debug-livepatch-develUpgrade dtb-marvellUpgrade kernel-source-rtUpgrade kernel-kvmsmall-livepatch-develUpgrade kernel-default-baseUpgrade dtb-allwinnerUpgrade kernel-64kb-livepatch-develUpgrade ocfs2-kmp-64kbUpgrade reiserfs-kmp-defaultUpgrade gfs2-kmp-defaultUpgrade kernel-azure-extraUpgrade kernel-64kbUpgrade gfs2-kmp-64kbUpgrade kernel-docs-htmlUpgrade kernel-docsUpgrade dtb-amdUpgrade kernel-debugUpgrade kernel-default-develUpgrade kernel-azureUpgrade reiserfs-kmp-64kbUpgrade kernel-azure-vdsoUpgrade kernel-defaultUpgrade kernel-rt_debug-vdsoUpgrade kernel-default-vdsoUpgrade ocfs2-kmp-defaultUpgrade dtb-qcomUpgrade kernel-devel-azureUpgrade dtb-lgUpgrade kernel-rt-extraUpgrade kernel-rtUpgrade kernel-obs-buildUpgrade kernel-default-base-rebuildUpgrade kernel-obs-qaUpgrade kernel-azure-optionalUpgrade cluster-md-kmp-rtUpgrade kernel-default-optionalUpgrade kernel-kvmsmall-develUpgrade kernel-zfcpdumpUpgrade kernel-debug-vdsoUpgrade reiserfs-kmp-azureUpgrade kernel-kvmsmallUpgrade kernel-rt-develUpgrade dtb-mediatekUpgrade kernel-rt-vdsoUpgrade dtb-armUpgrade dtb-amlogicUpgrade dtb-alteraUpgrade dlm-kmp-64kbUpgrade cluster-md-kmp-azureUpgrade kernel-default-extraUpgrade kernel-sourceUpgrade kernel-macrosUpgrade kernel-develUpgrade kernel-azure-livepatch-develUpgrade dtb-apmUpgrade kernel-source-azureUpgrade gfs2-kmp-rtUpgrade dtb-rockchipUpgrade dtb-exynosUpgrade kernel-azure-develUpgrade kselftests-kmp-64kbUpgrade kernel-syms-azureUpgrade gfs2-kmp-azureUpgrade dtb-xilinxUpgrade kernel-rt-livepatchUpgrade kernel-devel-rtUpgrade ocfs2-kmp-rtUpgrade kernel-rt_debug-develUpgrade dtb-cavium | Aug 9, 2024 | Apr 28, 2024 |
| Ubuntu | — | Upgrade linux-gcp-5.4Upgrade linux-oracleUpgrade linux-azure-5.4Upgrade linux-hwe-5.15Upgrade linux-intel-iotgUpgrade linux-kvmUpgrade linux-iotUpgrade linux-realtimeUpgrade linux-nvidiaUpgrade linux-aws-fipsUpgrade linux-azureUpgrade linux-azure-fipsUpgrade linux-oracle-5.15Upgrade linux-gcp-5.15Upgrade linux-gcp-fipsUpgrade linux-azure-fdeUpgrade linux-hwe-5.4Upgrade linux-ibmUpgrade linux-gkeopUpgrade linux-azure-5.15Upgrade linux-intel-iotg-5.15Upgrade linux-gkeop-5.15Upgrade linux-raspi-5.4Upgrade linux-oracle-5.4Upgrade linuxUpgrade linux-ibm-5.4Upgrade linux-lowlatencyUpgrade linux-bluefieldUpgrade linux-gkeUpgrade linux-aws-5.4Upgrade linux-fipsUpgrade linux-awsUpgrade linux-lowlatency-hwe-5.15Upgrade linux-riscv-5.15Upgrade linux-gcpUpgrade linux-raspiUpgrade linux-aws-5.15 | 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