From: netdev-bot+sashiko@kernel.org
To: jhs@mojatatu.com
Cc: netdev@vger.kernel.org, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, jiri@resnulli.us,
vinicius.gomes@intel.com, horms@kernel.org, victor@mojatatu.com,
xiangxia.m.yue@gmail.com, zdi-disclosures@trendmicro.com,
hybris@mojatatu.ai, stable@vger.kernel.org
Subject: Re: [PATCH net] net: cap skb->queue_mapping when the tx queue is picked
Date: Tue, 22 Sep 2026 14:03:39 +0000 [thread overview]
Message-ID: <179008581937.2160803.7117814290574262942@kernel.org> (raw)
In-Reply-To: <QDISC-9R8V.v1.20260921065103@mojatatu.com>
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 0 · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The commit message's justification and reproducer cannot reach
the code the patch changes, so the patch's stated bug (and its…
--
net: cap skb->queue_mapping when the tx queue is picked
This stores the value returned by netdev_cap_txqueue() back into
skb->queue_mapping in netdev_tx_queue_mapping(), so that later readers of
skb_get_queue_mapping() on the xmit path see an in-range index. The
changelog attributes the out-of-range mapping to an skbedit + mirred
egress redirect from a device with more TX queues to one with fewer.
> diff --git a/net/core/dev.c b/net/core/dev.c
> index c67900354fa64..736b3664b6354 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -4404,9 +4404,14 @@ EXPORT_SYMBOL(dev_loopback_xmit);
> static struct netdev_queue *
> netdev_tx_queue_mapping(struct net_device *dev, struct sk_buff *skb)
> {
> - int qm = skb_get_queue_mapping(skb);
> + int queue = skb_get_queue_mapping(skb);
> + int capped;
>
> - return netdev_get_tx_queue(dev, netdev_cap_txqueue(dev, qm));
> + capped = netdev_cap_txqueue(dev, queue);
> + if (unlikely(capped != queue))
> + skb_set_queue_mapping(skb, capped);
> +
> + return netdev_get_tx_queue(dev, capped);
> }
[Severity: High]
Can the reproducer in the changelog actually reach this function?
netdev_tx_queue_mapping() has a single caller, and it is gated on the
per-CPU (or per-task, on PREEMPT_RT) skip_txqueue flag:
net/core/dev.c:__dev_queue_xmit() {
...
if (static_branch_unlikely(&egress_needed_key)) {
...
netdev_xmit_skip_txqueue(false);
nf_skip_egress(skb, true);
skb = sch_handle_egress(skb, &rc, dev);
if (!skb)
goto out;
nf_skip_egress(skb, false);
if (netdev_xmit_txqueue_skipped())
txq = netdev_tx_queue_mapping(dev, skb);
}
...
}
The clear at netdev_xmit_skip_txqueue(false) runs unconditionally at the
top of that block, in every egress-enabled frame.
The described redirect enters the target device through a nested
__dev_queue_xmit():
tcf_mirred_forward()
tcf_dev_queue_xmit(skb, dev_queue_xmit)
dev_queue_xmit()
__dev_queue_xmit() /* for qb */
Since clsact on qa has already raised egress_needed_key, that nested
frame for qb takes the same block and clears the flag that skbedit set
while running on qa. netdev_xmit_txqueue_skipped() is then false, txq
stays NULL, and qb's queue comes from netdev_core_pick_tx(), which caps
and rewrites the mapping itself:
net/core/dev.c:netdev_core_pick_tx() {
...
queue_index = netdev_cap_txqueue(dev, queue_index);
}
skb_set_queue_mapping(skb, queue_index);
return netdev_get_tx_queue(dev, queue_index);
}
So by the time taprio_enqueue() runs:
net/sched/sch_taprio.c:taprio_enqueue() {
queue = skb_get_queue_mapping(skb);
child = q->qdiscs[queue];
the index it reads looks already in range for qb, on the patched and the
unpatched kernel alike. Does the quoted "BUG: KASAN: slab-out-of-bounds
in taprio_enqueue", the read 0 bytes past the 16-byte taprio_init
allocation, really come from this skbedit + mirred sequence?
A second point on the rationale:
So the decision is to cap the value where it is first trusted and
result is it fixes all downstream readers at once.
Is this site where the value is first trusted? The only in-tree setter of
the flag validates against the same device before arming it, and stores an
already capped value:
net/sched/act_skbedit.c:tcf_skbedit_act() {
...
if (params->flags & SKBEDIT_F_QUEUE_MAPPING &&
skb->dev->real_num_tx_queues > params->queue_mapping) {
#ifdef CONFIG_NET_EGRESS
netdev_xmit_skip_txqueue(true);
#endif
skb_set_queue_mapping(skb, tcf_skbedit_hash(params, skb));
}
and tcf_skbedit_hash() ends with:
return netdev_cap_txqueue(skb->dev, queue_mapping);
With that, capped != queue in the new code seems to require either
real_num_tx_queues shrinking concurrently (the index still being below
dev->num_tx_queues, so still inside dev->_tx[] and taprio's q->qdiscs[]),
or something rewriting skb->queue_mapping later in the same egress run.
A path that does look able to deliver a genuinely out-of-range value to
the new statement is a tc BPF program writing skb->queue_mapping after
skbedit armed the flag on the same device, since
tc_cls_act_is_valid_access() permits BPF_WRITE of that field and
bpf_convert_ctx_access() emits the store. Would describing that (or a
similar in-frame rewrite) instead of the cross-device mirred path make the
Fixes: tag and the reported scenario verifiable for reviewers and stable
backporters?
Also, this isn't a bug, but the changelog says:
Another approach was to cap it in skbedit; cannot work: the
redirect target, whose queue count bounds the mapping, is not known
when the action runs, and act_mirred sets skb->dev afterwards.
there is a double space after the semicolon.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-9R8V.v1.20260921065103%40mojatatu.com
next prev parent reply other threads:[~2026-09-22 14:03 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 14:02 [PATCH net] net: cap skb->queue_mapping when the tx queue is picked Jamal Hadi Salim
2026-09-21 14:42 ` Eric Dumazet
2026-09-21 19:57 ` Jamal Hadi Salim
2026-09-22 14:03 ` netdev-bot+sashiko [this message]
2026-09-22 21:33 ` Jamal Hadi Salim
2026-09-24 8:06 ` Jamal Hadi Salim
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=179008581937.2160803.7117814290574262942@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=hybris@mojatatu.ai \
--cc=jhs@mojatatu.com \
--cc=jiri@resnulli.us \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
--cc=victor@mojatatu.com \
--cc=vinicius.gomes@intel.com \
--cc=xiangxia.m.yue@gmail.com \
--cc=zdi-disclosures@trendmicro.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox