CVE-2026-98797

CVE-2026-98797

published October 18, 2026

CVSS
—
EPSS
0%
Percentile
4.8
In the wild
Unconfirmed
What it is

In the Linux kernel, the following vulnerability has been resolved:

net: cap skb->queue_mapping when the tx queue is picked

skbedit can set skb->queue_mapping and raise the per-CPU skip_txqueue

flag so __dev_queue_xmit() honours the mapping. __dev_queue_xmit()

cleared the flag before sch_handle_egress() and only read it afterwards,

so the flag was not confined to the xmit that set it: a nested xmit

(mirred redirect or mirror, or a drop after skbedit) could set the flag

and the outer xmit would consume it for an skb that never went through

skbedit.

A forwarded packet still carries the ingress NIC's rx_queue + 1 in

skb->queue_mapping, so the outer device then indexes its tx queue state

with that stale value. Taprio's child array q->qdiscs[] is sized to the

device's queue count, so taprio_enqueue() indexes past its allocation

and dereferences the result as a struct Qdisc *.

We (ab)use the skb->nf_skip_egress which means "skip netfilter egress

for this packet" to tag to "am I in tc egress?". Despite the overload

I dont see it as a conflict since the marker is set only around the

single sch_handle_egress() call and ingress path is guarded by

tc_at_ingress.

I will send a followup(net-next) patch once this hits net-next to

rename the skb->nf_skip_egress bit/flag to skb->skip_egress

Arm the flag only from the egress classifier that can use it: raise

skip_txqueue from tcf_skbedit_act() only when it runs inside

sch_handle_egress(), thanks to skb->nf_skip_egress. An egress qdisc

classifier runs in q->enqueue(), after the tx queue has been picked,

so a mapping it sets cannot affect the current packet; arming the flag

there only pollutes it for a later xmit. Then own the flag for the xmit

frame the egress hook runs in: save the incoming value and clear it just

before sch_handle_egress(), and restore it after the hook - on the

consumed (drop) path, or, in the same call that reads it, on the

surviving path. The save and the restores stay inside the

egress_needed_key static branch, so a packet pays for them only when

egress hooks are active (2f1e85b1aee4).

Store the value netdev_cap_txqueue() selected back into skb->queue_mapping

in netdev_tx_queue_mapping(), as netdev_core_pick_tx() already does, so

the skip_txqueue path never hands a later reader on the xmit path a

mapping the device cannot serve. A store made still later in the same

frame, by a tc BPF program attached to a transmit qdisc, is outside this

path and is not re-capped; a separate followup will resolve that path.

netdev_xmit_skip_txqueue() returns the previous flag value so the

save-and-clear is one call, and a no-op stub is provided when

CONFIG_NET_EGRESS is disabled. skb->nf_skip_egress is compiled under

CONFIG_NET_EGRESS rather than CONFIG_NETFILTER_SKIP_EGRESS, so

skb_at_tc_egress() is valid whenever the egress path is built.

A local user in a network namespace can redirect a packet from a device

with more TX queues to one with fewer after setting a mapping valid only

on the larger device. That reaches these reads and, under KASAN, faults

with "slab-out-of-bounds in taprio_enqueue".

Conditions to recreate the bug: the report's own trigger is a local user

with CAP_NET_ADMIN in a network namespace, so no eBPF program is needed.

With CONFIG_NET_SCH_TAPRIO=y, CONFIG_NET_ACT_SKBEDIT=y,

CONFIG_NET_ACT_MIRRED=y, CONFIG_NET_CLS_MATCHALL=y,

CONFIG_NET_SCH_PRIO=y and KASAN enabled, create qa (3 queues), qb

(2 queues) and qc (1 queue) as dummy devices; put a taprio root on qb

(num_tc 1, queues 2@0) and clsact on all three; then add an egress

matchall filter on every device. On qa: "action skbedit queue_mapping 2

pipe action mirred egress redirect dev qb". On qb: "action mirred egress

mirror dev qc". On qc: "action skbedit queue_mapping 0 pipe". Send one

packet out qa. qc's skbedit sets the flag while qb's outer xmit is in

flight; without the fix qb consumes it and reads its two-entry taprio

child array with the forwarded packet's stale mapping. A qc whose

skb

---truncated---

The record
Technical detail
CVSS
Not scored
CVSS v4.0
Not supplied
EPSS
0.00160 · 4.8th percentile
Published
2026-10-18T20:17Z
References (4)
EPSS history
Timeline
  • 20 OCT 03:34Z
    EPSS moved — → 0%
    epss
  • 18 OCT 15:48Z
    net: cap skb->queue_mapping when the tx queue is picked
    cvelistv5
  • 18 OCT 15:48Z
    net: cap skb->queue_mapping when the tx queue is picked
    cvelistv5