Thread (29 messages) 29 messages, 5 authors, 3d ago

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..0bd73c5072a90d3e952d0a724461adcf0307592e
100644
--- 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!
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help