---
id: CVE-2026-98797
title: 'net: cap skb->queue_mapping when the tx queue is picked'
summary: |-
  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 ma…
severity: none
vendor: Linux
product: Linux
affected:
  - >-
    Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c <
    c6ec35c8267c84c2094cb485db20c06384fc2bcc
  - >-
    Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c <
    2f581814e4e3ea6a5e98f49813dc4c68444a0c4a
  - >-
    Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c <
    f99de42f5c6f8d088063817dad82c3334e87c570
  - >-
    Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c <
    ea4d4b5dddb5121e64f56fd8e0720bd8b447b63d
  - Linux 5.19
published: '2026-10-18'
updated: '2026-10-18'
sourceUpdated: '2026-10-18T15:48:41.613Z'
source: CVEORG
sourceUrl: 'https://www.cve.org/CVERecord?id=CVE-2026-98797'
references:
  - url: 'https://git.kernel.org/stable/c/c6ec35c8267c84c2094cb485db20c06384fc2bcc'
  - url: 'https://git.kernel.org/stable/c/2f581814e4e3ea6a5e98f49813dc4c68444a0c4a'
  - url: 'https://git.kernel.org/stable/c/f99de42f5c6f8d088063817dad82c3334e87c570'
  - url: 'https://git.kernel.org/stable/c/ea4d4b5dddb5121e64f56fd8e0720bd8b447b63d'
tags:
  - cve.org
ingestedAt: '2026-10-18T16:47:32.483Z'
---

## Overview

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---

## Affected

- `Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c < c6ec35c8267c84c2094cb485db20c06384fc2bcc`
- `Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c < 2f581814e4e3ea6a5e98f49813dc4c68444a0c4a`
- `Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c < f99de42f5c6f8d088063817dad82c3334e87c570`
- `Linux >= 2f1e85b1aee459b7d0fd981839042c6a38ffaf0c < ea4d4b5dddb5121e64f56fd8e0720bd8b447b63d`
- `Linux 5.19`

## Remediation

Refer to the linked advisories for vendor-supplied fixes and affected version ranges.
