Re: [PATCH net v2 3/6] net/sched: act_mirred: reject redirects without a link-layer header
flat view
From: Eric Dumazet <edumazet@kernel.org>
Date: 2026-10-23 13:17:28
Also in:
stable
Subsystem:
networking [general], tc subsystem, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim, Jiri Pirko, Linus Torvalds
Le ven. 23 oct. 2026 à 13:59, Jamal Hadi Salim [off-list ref] a écrit :
quoted hunk ↗ jump to hunk
The issue: tcf_mirred_to_dev() may redirect a packet that has no link-layer header to a device that expects one. TUN builds a valid L3 skb with mac_len == 0; mirred then pushes zero bytes and the IP header is parsed as Ethernet by eth_type_trans(). The same happens after a VLAN POP_ETH or MPLS POP chain whose producer did not leave a full inner Ethernet header. The Fix: After the existing push/pull adjustment, when the target expects data at the MAC header, require a link-layer header of at least dev->min_header_len bytes and pull it into the linear area. Drop the packet otherwise. This mirrors the check bpf_redirect() already performs and keeps the legitimate push_eth-then-mirred case working. Conditions to recreate the bug: - create a TUN device with IFF_TUN | IFF_VNET_HDR | IFF_NO_PI; - attach egress mirred redirect to an Ethernet device (for example lo); - write a virtio_net_hdr with hdr_len=1 and an 8192-byte payload. The unfixed kernel parses the IP header as Ethernet and can BUG in eth_type_trans() via loopback_xmit. Fixes: 53592b364001 ("net/sched: act_mirred: Implement ingress actions") Suggested-by: Eric Dumazet <edumazet@kernel.org> Suggested-by: Willem de Bruijn <willemdebruijn.kernel@gmail.com> Cc: <redacted> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> --- net/sched/act_mirred.c | 7 +++++++ 1 file changed, 7 insertions(+)diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 553342c55cf7..e3e0e4aa70a1 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c@@ -316,6 +316,11 @@ static int tcf_mirred_to_dev(struct sk_buff *skb, struct tcf_mirred *m, } } + if (!expects_nh && + (unlikely(skb_network_offset(skb_to_send) < dev->min_header_len) || + !pskb_may_pull(skb_to_send, dev->min_header_len))) + goto err_cant_do; +
Oops, sorry this breaks tools/testing/selftests/net/forwarding/tc_mpls_l2vpn.sh My bad, the skb_network_offset() part I suggested in v1 is wrong. Please remove it:
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index b0390b08600c4a709b18f6d92aebe6629081c735..0bd73c5072a90d3e952d0a724461adcf0307592e100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c@@ -317,8 +317,7 @@ static int tcf_mirred_to_dev(struct sk_buff *skb,struct tcf_mirred *m,
}
if (!expects_nh &&
- (unlikely(skb_network_offset(skb_to_send) < dev->min_header_len) ||
- !pskb_may_pull(skb_to_send, dev->min_header_len)))
+ !pskb_may_pull(skb_to_send, dev->min_header_len))
goto err_cant_do;
skb_to_send->skb_iif = skb->dev->ifindex;
Keep only the pskb_may_pull() which is enough to prevent
eth_type_trans() from crashing on a short linear part.
Thanks!