All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack
@ 2026-10-28 12:26 Eric Dumazet
  2026-10-28 12:26 ` [PATCH net v2 1/5] net: add eth_type_trans_careful() Eric Dumazet
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Eric Dumazet @ 2026-10-28 12:26 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei

eth_type_trans() assumes ETH_HLEN bytes are present in skb->head.
NIC drivers always provide this, and they should keep using the fast
version, without an extra pskb_may_pull().

Devices looping skbs from their transmit path back to their receive
path get skbs built by the stack instead. tc actions (act_vlan pop_eth,
act_ife decode), BPF helpers (bpf_skb_change_head() before a redirect)
or OVS actions (pop_eth followed by pop_mpls/pop_nsh) can leave fewer
than ETH_HLEN bytes in the linear part, and eth_type_trans() then hits
the BUG() in __skb_pull().

Instead of fixing every producer, or adding a check to all
eth_type_trans() users, fix the few consumers exposed to this:

- Patch 1 adds eth_type_trans_careful(), which pulls the Ethernet
  header first and returns a drop reason on failure.
- Patch 2 uses it in loopback_xmit().
- Patch 3 uses it in __dev_forward_skb2(), used by BPF redirects to
  ingress and by veth, macvlan, ipvlan, netdevsim and l2tp_eth.
- Patch 4 uses it in OVS internal_dev_recv(), covering both the MPLS
  (TEB) and NSH pop cases at once (only the MPLS case was tested).
- Patch 5 (from Jamal) fixes act_ife decode on egress, which was
  consuming the inner Ethernet header. This is no longer a crash after
  patch 2, but egress decode never delivered a correct frame.

Other eth_type_trans() users already pull the header or never see
such skbs:
- vrf_process_v{4,6}_outbound() already pull ETH_HLEN + IP header
  before vrf_local_xmit().
- tun already uses pskb_may_pull_reason(skb, ETH_HLEN).
- XDP: bpf_xdp_adjust_head() and bpf_xdp_adjust_tail() keep at least
  ETH_HLEN bytes in the linear part, and multi-buffer tail shrinking
  only trims frags.

Tested under virtme-ng with AF_PACKET reproducers. Without the series,
all four cases crash in eth_type_trans():
- lo egress "action vlan pop_eth", eth/eth/8192 bytes frame
- lo egress "action ife decode pipe", IFE frame with 8192 bytes payload
- lo egress "action vlan pop_eth continue", then a BPF program doing
  bpf_skb_change_head(skb, 1, 0) + bpf_redirect(veth1, BPF_F_INGRESS)
- OVS flow "pop_eth,pop_mpls(0x6558),0" to the internal port,
  eth/mpls/eth/4096 bytes frame
With the series, no crash. An ICMP echo inside an IFE frame decoded
on lo egress is now received and answered. Normal traffic on lo,
veth (including 8000 byte pings) and vrf is unchanged.

v2:
- Patch 3: update the empty_skb BPF selftest. At lwt_xmit, its
  "veth ETH_HLEN+1" packet is a 1-byte skb, which is now dropped on
  veth ingress, as veth_xmit() already does on egress (BPF CI).
- Rebased on latest net, collected tags from Aaron, Willem and Jamal.
- No kernel code change.

Link: https://lore.kernel.org/netdev/20261005052249.1914367-2-weir@nebusec.ai/
Link: https://lore.kernel.org/netdev/ACT-N6N4.v3.r0.20261023200137-4@mojatatu.com/
v1: https://lore.kernel.org/netdev/20261027082604.1485903-1-edumazet@kernel.org/

Eric Dumazet (4):
  net: add eth_type_trans_careful()
  loopback: use eth_type_trans_careful()
  net: use eth_type_trans_careful() in __dev_forward_skb2()
  openvswitch: use eth_type_trans_careful() in internal_dev_recv()

Jamal Hadi Salim (1):
  net/sched: act_ife: do not consume the inner header on egress

 drivers/net/loopback.c                        |  8 +++++-
 include/linux/etherdevice.h                   | 28 +++++++++++++++++++
 net/core/dev.c                                | 18 ++++++++----
 net/openvswitch/vport-internal_dev.c          |  8 +++++-
 net/sched/act_ife.c                           |  4 +++
 .../selftests/bpf/prog_tests/empty_skb.c      | 19 ++++++++-----
 6 files changed, 71 insertions(+), 14 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH net v2 1/5] net: add eth_type_trans_careful()
  2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
@ 2026-10-28 12:26 ` Eric Dumazet
  2026-10-28 12:27 ` [PATCH net v2 2/5] loopback: use eth_type_trans_careful() Eric Dumazet
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Eric Dumazet @ 2026-10-28 12:26 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei

eth_type_trans() assumes ETH_HLEN bytes are present in skb->head.
NIC drivers always provide this, and they should keep using the fast
version.

Devices looping skbs from their transmit path back to their receive
path get skbs built by the stack instead. Their link-layer header
might have been popped by tc actions (act_vlan pop_eth, act_ife decode)
or OVS actions (pop_eth + pop_mpls / pop_nsh), leaving fewer than
ETH_HLEN bytes in the linear part. eth_type_trans() then hits
the BUG() in __skb_pull().

Add eth_type_trans_careful(), which first pulls the Ethernet header,
and returns a drop reason on failure, so that the few devices exposed
to this can drop such packets.

Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 include/linux/etherdevice.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index df8f88f63a7063fbd1df5248d2fc02c859a7bc74..1f833ebd71ed917d138ec1e64c29689ae7dd0dd5 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -38,6 +38,34 @@ int fwnode_get_mac_address(struct fwnode_handle *fwnode, char *addr);
 
 u32 eth_get_headlen(const struct net_device *dev, const void *data, u32 len);
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
+
+/**
+ * eth_type_trans_careful - eth_type_trans() for skbs coming from the stack
+ * @skb: buffer, possibly with less than ETH_HLEN bytes in its linear area
+ * @dev: receiving network device
+ *
+ * eth_type_trans() expects ETH_HLEN bytes in skb->head, which NIC drivers
+ * provide. Devices looping skbs from their transmit path back to the
+ * receive path (loopback, OVS internal ports) get skbs built by the stack,
+ * whose link-layer header might have been popped by tc or OVS actions.
+ *
+ * Sets skb->protocol on success.
+ *
+ * Return: SKB_NOT_DROPPED_YET on success, or a drop reason. In the latter
+ * case, the caller must free @skb.
+ */
+static inline enum skb_drop_reason
+eth_type_trans_careful(struct sk_buff *skb, struct net_device *dev)
+{
+	enum skb_drop_reason reason = pskb_may_pull_reason(skb, ETH_HLEN);
+
+	if (unlikely(reason))
+		return reason;
+
+	skb->protocol = eth_type_trans(skb, dev);
+	return SKB_NOT_DROPPED_YET;
+}
+
 extern const struct header_ops eth_header_ops;
 
 int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net v2 2/5] loopback: use eth_type_trans_careful()
  2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
  2026-10-28 12:26 ` [PATCH net v2 1/5] net: add eth_type_trans_careful() Eric Dumazet
@ 2026-10-28 12:27 ` Eric Dumazet
  2026-10-28 18:48   ` Willem de Bruijn
  2026-10-28 12:27 ` [PATCH net v2 3/5] net: use eth_type_trans_careful() in __dev_forward_skb2() Eric Dumazet
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Eric Dumazet @ 2026-10-28 12:27 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei,
	Vega

tc egress actions can leave an skb with fewer than ETH_HLEN bytes in
its linear part. loopback_xmit() then crashes in eth_type_trans():

  tc qdisc add dev lo clsact
  tc filter add dev lo egress matchall action vlan pop_eth
  # AF_PACKET SOCK_RAW: eth / eth / 8192 bytes of payload

  kernel BUG at include/linux/skbuff.h:2839!
  RIP: 0010:eth_type_trans (include/linux/etherdevice.h:635 net/ethernet/eth.c:163)
  Call Trace:
   loopback_xmit (drivers/net/loopback.c:87)
   dev_hard_start_xmit (include/linux/netdevice.h:5455 include/linux/netdevice.h:5464 net/core/dev.c:4057 net/core/dev.c:4073)
   __dev_queue_xmit (net/core/dev.c:5066)
   packet_sendmsg (net/packet/af_packet.c:3157 net/packet/af_packet.c:3189)

The same happens with "action ife decode" on lo egress.

Use eth_type_trans_careful(), and drop the packet if the Ethernet
header can not be pulled.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Vega <vega@nebusec.ai>
Link: https://lore.kernel.org/netdev/20261005052249.1914367-2-weir@nebusec.ai/
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 drivers/net/loopback.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 55ecd5ebac0f21b61b64373c429a6f9ba5d15c8e..8a6cb34e6b5f02c88dfb0c6bf112068c4f51fec1 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -70,6 +70,7 @@ EXPORT_SYMBOL(blackhole_netdev);
 static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 				 struct net_device *dev)
 {
+	enum skb_drop_reason reason;
 	int len;
 
 	skb_tx_timestamp(skb);
@@ -84,7 +85,12 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 	 */
 	skb_dst_force(skb);
 
-	skb->protocol = eth_type_trans(skb, dev);
+	reason = eth_type_trans_careful(skb, dev);
+	if (unlikely(reason)) {
+		dev_core_stats_tx_dropped_inc(dev);
+		kfree_skb_reason(skb, reason);
+		return NETDEV_TX_OK;
+	}
 
 	len = skb->len;
 	if (likely(__netif_rx(skb) == NET_RX_SUCCESS))
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net v2 3/5] net: use eth_type_trans_careful() in __dev_forward_skb2()
  2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
  2026-10-28 12:26 ` [PATCH net v2 1/5] net: add eth_type_trans_careful() Eric Dumazet
  2026-10-28 12:27 ` [PATCH net v2 2/5] loopback: use eth_type_trans_careful() Eric Dumazet
@ 2026-10-28 12:27 ` Eric Dumazet
  2026-10-28 19:03   ` Willem de Bruijn
  2026-10-28 12:27 ` [PATCH net v2 4/5] openvswitch: use eth_type_trans_careful() in internal_dev_recv() Eric Dumazet
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Eric Dumazet @ 2026-10-28 12:27 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei

A tc egress BPF program can push a tiny link-layer header with
bpf_skb_change_head() on an skb whose head is almost empty, then
redirect it to an Ethernet device ingress. __bpf_redirect_common()
only checks mac_header < network_header, and __dev_forward_skb2()
crashes in eth_type_trans():

  tc filter add dev lo egress pref 1 matchall action vlan pop_eth continue
  tc filter add dev lo egress pref 2 bpf da obj prog.o
  # prog: bpf_skb_change_head(skb, 1, 0);
  #       return bpf_redirect(veth1_ifindex, BPF_F_INGRESS);
  # AF_PACKET SOCK_RAW on lo: eth / eth / 8192 bytes of payload

  kernel BUG at include/linux/skbuff.h:2839!
  RIP: 0010:eth_type_trans (include/linux/etherdevice.h:635 net/ethernet/eth.c:163)
  Call Trace:
   __dev_forward_skb2 (net/core/dev.c:2507)
   dev_forward_skb_nomtu (net/core/dev.c:2546)
   __dev_queue_xmit (net/core/dev.c:4738 net/core/dev.c:4998)
   packet_sendmsg (net/packet/af_packet.c:3157 net/packet/af_packet.c:3189)

Use eth_type_trans_careful(), and drop the packet if the Ethernet
header can not be pulled. This also covers other dev_forward_skb()
users (veth, macvlan, ipvlan, netdevsim, l2tp_eth).

Update the empty_skb BPF selftest: at lwt_xmit, BPF_PROG_TEST_RUN
strips the Ethernet header, so the "veth ETH_HLEN+1" packet is a 1-byte
skb. Redirecting it to veth ingress used to read the Ethernet header
past skb->tail and deliver a 1-byte frame; it is now dropped with
NET_RX_DROP, as veth_xmit() already does at egress.

Fixes: 3a0af8fd61f9 ("bpf: BPF for lightweight tunnel infrastructure")
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 net/core/dev.c                                | 18 +++++++++++++-----
 .../selftests/bpf/prog_tests/empty_skb.c      | 19 ++++++++++++-------
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index b3622e532f269333ed62e31fbca0f6ac56dcde8f..a51d53491fa23158cb31fa4764f41f0ad9ecc978 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2501,14 +2501,22 @@ EXPORT_SYMBOL_GPL(is_skb_forwardable);
 static int __dev_forward_skb2(struct net_device *dev, struct sk_buff *skb,
 			      bool check_mtu)
 {
-	int ret = ____dev_forward_skb(dev, skb, check_mtu);
+	enum skb_drop_reason reason;
+	int ret;
+
+	ret = ____dev_forward_skb(dev, skb, check_mtu);
+	if (unlikely(ret))
+		return ret;
 
-	if (likely(!ret)) {
-		skb->protocol = eth_type_trans(skb, dev);
-		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+	reason = eth_type_trans_careful(skb, dev);
+	if (unlikely(reason)) {
+		dev_core_stats_rx_dropped_inc(dev);
+		kfree_skb_reason(skb, reason);
+		return NET_RX_DROP;
 	}
+	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 
-	return ret;
+	return 0;
 }
 
 int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
diff --git a/tools/testing/selftests/bpf/prog_tests/empty_skb.c b/tools/testing/selftests/bpf/prog_tests/empty_skb.c
index c9fcb70cbafbce571d7826e233920193625dead1..a3938c16557b140e3ee5c116139cf8b636f85e35 100644
--- a/tools/testing/selftests/bpf/prog_tests/empty_skb.c
+++ b/tools/testing/selftests/bpf/prog_tests/empty_skb.c
@@ -24,7 +24,7 @@ void test_empty_skb(void)
 		int *ifindex;
 		int err;
 		int ret;
-		int lwt_egress_ret; /* expected retval at lwt/egress */
+		int lwt_ret; /* expected retval at lwt */
 		__be16 h_proto;
 		bool success_on_tc;
 		bool adjust_room;
@@ -82,7 +82,7 @@ void test_empty_skb(void)
 			.data_size_in = sizeof(eth_hlen),
 			.ifindex = &veth_ifindex,
 			.ret = -ERANGE,
-			.lwt_egress_ret = -ERANGE,
+			.lwt_ret = -ERANGE,
 			.success_on_tc = true,
 		},
 		{
@@ -96,17 +96,23 @@ void test_empty_skb(void)
 			.data_size_in = sizeof(eth_hlen),
 			.ifindex = &ipip_ifindex,
 			.ret = -ERANGE,
-			.lwt_egress_ret = -ERANGE,
+			.lwt_ret = -ERANGE,
 		},
 
-		/* ETH_HLEN+1-sized packet should be redirected. */
+		/* ETH_HLEN+1-sized packet should be redirected at TC.
+		 * At LWT, the Ethernet header is not part of the skb, and
+		 * a 1-byte packet is too short for an Ethernet device.
+		 */
 
 		{
 			.msg = "veth ETH_HLEN+1 packet ingress",
 			.data_in = eth_hlen_pp,
 			.data_size_in = sizeof(eth_hlen_pp),
 			.ifindex = &veth_ifindex,
-			.lwt_egress_ret = 1, /* veth_xmit NET_XMIT_DROP */
+			/* lwt: skb->len=1, dropped by veth_xmit() at egress
+			 * and by __dev_forward_skb2() at ingress.
+			 */
+			.lwt_ret = 1, /* NET_XMIT_DROP / NET_RX_DROP */
 		},
 		{
 			.msg = "ipip ETH_HLEN+1 packet ingress",
@@ -144,7 +150,6 @@ void test_empty_skb(void)
 			eth_hlen.h_proto = tests[i].h_proto;
 
 		bpf_object__for_each_program(prog, bpf_obj->obj) {
-			bool at_egress = strstr(bpf_program__name(prog), "egress") != NULL;
 			bool at_tc = !strncmp(bpf_program__section_name(prog), "tc", 2);
 			bool is_adjust_room = !strcmp(bpf_program__name(prog), "tc_adjust_room");
 			int expected_ret;
@@ -153,7 +158,7 @@ void test_empty_skb(void)
 			if (tests[i].adjust_room != is_adjust_room)
 				continue;
 
-			expected_ret = at_egress && !at_tc ? tests[i].lwt_egress_ret : tests[i].ret;
+			expected_ret = at_tc ? tests[i].ret : tests[i].lwt_ret;
 
 			tattr.data_in = tests[i].data_in;
 			tattr.data_size_in = tests[i].data_size_in;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net v2 4/5] openvswitch: use eth_type_trans_careful() in internal_dev_recv()
  2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
                   ` (2 preceding siblings ...)
  2026-10-28 12:27 ` [PATCH net v2 3/5] net: use eth_type_trans_careful() in __dev_forward_skb2() Eric Dumazet
@ 2026-10-28 12:27 ` Eric Dumazet
  2026-10-28 19:04   ` Willem de Bruijn
  2026-10-28 12:27 ` [PATCH net v2 5/5] net/sched: act_ife: do not consume the inner header on egress Eric Dumazet
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Eric Dumazet @ 2026-10-28 12:27 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei

OVS actions like pop_eth followed by pop_mpls(ETH_P_TEB) or pop_nsh
can expose an inner Ethernet header which is not in the linear part
of the skb. Output to an internal port then crashes in eth_type_trans():

  flow: in_port(0),eth(),eth_type(0x8847),mpls(lse=0x00010140)
  actions: pop_eth,pop_mpls(0x6558),0
  # AF_PACKET SOCK_RAW on dp0: eth / mpls / eth / 4096 bytes of payload

  kernel BUG at include/linux/skbuff.h:2839!
  RIP: 0010:eth_type_trans (include/linux/etherdevice.h:635 net/ethernet/eth.c:163)
  Call Trace:
   internal_dev_recv (net/openvswitch/vport-internal_dev.c:202) openvswitch
   do_execute_actions (net/openvswitch/actions.c:1296) openvswitch
   ovs_execute_actions (net/openvswitch/actions.c:1606) openvswitch
   ovs_dp_process_packet (net/openvswitch/datapath.c:310) openvswitch
   ovs_vport_receive (net/openvswitch/vport.c:448) openvswitch
   internal_dev_xmit (net/openvswitch/vport-internal_dev.c:42) openvswitch
   dev_hard_start_xmit (include/linux/netdevice.h:5455 include/linux/netdevice.h:5464 net/core/dev.c:4057 net/core/dev.c:4073)
   __dev_queue_xmit (net/core/dev.c:5066)
   packet_sendmsg (net/packet/af_packet.c:3157 net/packet/af_packet.c:3189)

Use eth_type_trans_careful(), and drop the packet if the Ethernet
header can not be pulled. This covers all OVS actions at the consumer,
instead of fixing each producer.

Fixes: b2d0f5d5dc53 ("openvswitch: enable NSH support")
Fixes: f66b53fdbb22 ("openvswitch: New MPLS actions for layer 2 tunnelling")
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
 net/openvswitch/vport-internal_dev.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c
index 77a16d5ebd54343c80a2def261aadcb8ff0d1274..8f035087f0eec80eddf6b493cf5ba7915a3e01c6 100644
--- a/net/openvswitch/vport-internal_dev.c
+++ b/net/openvswitch/vport-internal_dev.c
@@ -188,6 +188,7 @@ static void internal_dev_destroy(struct vport *vport)
 static int internal_dev_recv(struct sk_buff *skb)
 {
 	struct net_device *netdev = skb->dev;
+	enum skb_drop_reason reason;
 
 	if (unlikely(!(netdev->flags & IFF_UP))) {
 		kfree_skb(skb);
@@ -199,7 +200,12 @@ static int internal_dev_recv(struct sk_buff *skb)
 	nf_reset_ct(skb);
 
 	skb->pkt_type = PACKET_HOST;
-	skb->protocol = eth_type_trans(skb, netdev);
+	reason = eth_type_trans_careful(skb, netdev);
+	if (unlikely(reason)) {
+		dev_core_stats_rx_dropped_inc(netdev);
+		kfree_skb_reason(skb, reason);
+		return NETDEV_TX_OK;
+	}
 	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 	dev_sw_netstats_rx_add(netdev, skb->len);
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH net v2 5/5] net/sched: act_ife: do not consume the inner header on egress
  2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
                   ` (3 preceding siblings ...)
  2026-10-28 12:27 ` [PATCH net v2 4/5] openvswitch: use eth_type_trans_careful() in internal_dev_recv() Eric Dumazet
@ 2026-10-28 12:27 ` Eric Dumazet
  2026-10-28 17:34 ` [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Alexei Starovoitov
  2026-10-29 16:30 ` patchwork-bot+netdevbpf
  6 siblings, 0 replies; 12+ messages in thread
From: Eric Dumazet @ 2026-10-28 12:27 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Jamal Hadi Salim,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jiri Pirko, dev, Willem de Bruijn, Ren Wei, stable, Eric Dumazet

From: Jamal Hadi Salim <jhs@mojatatu.com>

The issue:
tcf_ife_decode() unconditionally calls eth_type_trans(), which pulls
ETH_HLEN.  On egress this consumes the inner Ethernet header, and the
device receives an skb whose data points to the L3 header:

- loopback_xmit() parses L3 data as Ethernet: the "ethertype" comes
  from the inner IPv4 source address, and the decapsulated packet is
  dropped or misparsed.
- a real NIC transmits the frame without its Ethernet header.

(The __skb_pull() BUG this used to trigger in loopback_xmit() when the
remaining linear area was short is handled by "loopback: use
eth_type_trans_careful()".)

The Fix:
Parse the inner Ethernet header with eth_type_trans() in both directions,
then restore the egress data position and MAC length.  On ingress the
existing behavior is unchanged.  On egress, push the inner Ethernet header
back after parsing so the xmit path sees the original frame and later
actions see a consistent network header.

Conditions to recreate the bug:
- egress tc filter on lo: action ife decode pipe;
- AF_PACKET SOCK_RAW frame: outer Ethernet with ETH_P_IFE, IFE metadata,
  inner Ethernet + a valid IPv4 ICMP echo request to a local address;
- before this patch, no echo is received; after it, the echo is
  delivered and answered.

Fixes: ef6980b6becb ("introduce IFE action")
Cc: stable@vger.kernel.org
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
[edumazet: reworded changelog, the crash is now handled in loopback]
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
---
 net/sched/act_ife.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 2afd68983ece40d8cae6c96af86e2ea65be476bc..3946a9589bb8fcd296e6f1f9234c00238df4d954 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -769,6 +769,10 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
 
 	skb->protocol = eth_type_trans(skb, skb->dev);
 	skb_reset_network_header(skb);
+	if (!skb_at_tc_ingress(skb)) {
+		skb_push(skb, ETH_HLEN);
+		skb_reset_mac_len(skb);
+	}
 
 	return action;
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack
  2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
                   ` (4 preceding siblings ...)
  2026-10-28 12:27 ` [PATCH net v2 5/5] net/sched: act_ife: do not consume the inner header on egress Eric Dumazet
@ 2026-10-28 17:34 ` Alexei Starovoitov
  2026-10-28 19:31   ` Daniel Borkmann
  2026-10-29 16:30 ` patchwork-bot+netdevbpf
  6 siblings, 1 reply; 12+ messages in thread
From: Alexei Starovoitov @ 2026-10-28 17:34 UTC (permalink / raw)
  To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Andrew Lunn,
	Aaron Conole, Eelco Chaudron, Ilya Maximets, Jamal Hadi Salim,
	Jiri Pirko, dev, Willem de Bruijn, Ren Wei

On Wed, Oct 28, 2026 at 05:26 AM Eric Dumazet <edumazet@kernel.org> wrote:
> Other eth_type_trans() users already pull the header or never see
> such skbs:

netkit_xmit() has the same problem, I think.
It calls eth_skb_pull_mac() directly, not eth_type_trans().
It pulls ETH_HLEN before netkit_run(). The prog can shrink the linear
part after that:

  AF_PACKET SOCK_RAW on nk0          eth (ETH_P_IP) / eth / 8192 bytes
  tc egress on nk0
    vlan pop_eth                     skb_headlen() == 0
                                     skb_mac_header_len() == 0
  netkit_xmit()
    pskb_may_pull(skb, ETH_HLEN)     skb_headlen() == 14
    netkit_run()
      bpf_skb_adjust_room(skb, -1, BPF_ADJ_ROOM_MAC, 0)
        bpf_skb_generic_pop()        off == 0, skb_headlen() == 13
    eth_skb_pull_mac()               BUG() in __skb_pull()

It's an old bug and it doesn't block this series.
It can be a follow up.

Something like this (compile tested only):

diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c
index 82e608e..f093103 100644
--- a/drivers/net/netkit.c
+++ b/drivers/net/netkit.c
@@ -116,6 +116,9 @@ static netdev_tx_t netkit_xmit(struct sk_buff *skb, struct net_device *dev)
 	switch (ret) {
 	case NETKIT_NEXT:
 	case NETKIT_PASS:
+		/* The prog may have shrunk the linear part */
+		if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
+			goto drop;
 		eth_skb_pull_mac(skb);
 		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 		if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) {

For the series:
Acked-by: Alexei Starovoitov <ast@kernel.org>

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH net v2 2/5] loopback: use eth_type_trans_careful()
  2026-10-28 12:27 ` [PATCH net v2 2/5] loopback: use eth_type_trans_careful() Eric Dumazet
@ 2026-10-28 18:48   ` Willem de Bruijn
  0 siblings, 0 replies; 12+ messages in thread
From: Willem de Bruijn @ 2026-10-28 18:48 UTC (permalink / raw)
  To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei,
	Vega

Eric Dumazet wrote:
> tc egress actions can leave an skb with fewer than ETH_HLEN bytes in
> its linear part. loopback_xmit() then crashes in eth_type_trans():
> 
>   tc qdisc add dev lo clsact
>   tc filter add dev lo egress matchall action vlan pop_eth
>   # AF_PACKET SOCK_RAW: eth / eth / 8192 bytes of payload
> 
>   kernel BUG at include/linux/skbuff.h:2839!
>   RIP: 0010:eth_type_trans (include/linux/etherdevice.h:635 net/ethernet/eth.c:163)
>   Call Trace:
>    loopback_xmit (drivers/net/loopback.c:87)
>    dev_hard_start_xmit (include/linux/netdevice.h:5455 include/linux/netdevice.h:5464 net/core/dev.c:4057 net/core/dev.c:4073)
>    __dev_queue_xmit (net/core/dev.c:5066)
>    packet_sendmsg (net/packet/af_packet.c:3157 net/packet/af_packet.c:3189)
> 
> The same happens with "action ife decode" on lo egress.
> 
> Use eth_type_trans_careful(), and drop the packet if the Ethernet
> header can not be pulled.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: Vega <vega@nebusec.ai>
> Link: https://lore.kernel.org/netdev/20261005052249.1914367-2-weir@nebusec.ai/
> Signed-off-by: Eric Dumazet <edumazet@kernel.org>
> Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
> Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>

Reviewed-by: Willem de Bruijn <willemb@google.com>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH net v2 3/5] net: use eth_type_trans_careful() in __dev_forward_skb2()
  2026-10-28 12:27 ` [PATCH net v2 3/5] net: use eth_type_trans_careful() in __dev_forward_skb2() Eric Dumazet
@ 2026-10-28 19:03   ` Willem de Bruijn
  0 siblings, 0 replies; 12+ messages in thread
From: Willem de Bruijn @ 2026-10-28 19:03 UTC (permalink / raw)
  To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei

Eric Dumazet wrote:
> A tc egress BPF program can push a tiny link-layer header with
> bpf_skb_change_head() on an skb whose head is almost empty, then
> redirect it to an Ethernet device ingress. __bpf_redirect_common()
> only checks mac_header < network_header, and __dev_forward_skb2()
> crashes in eth_type_trans():
> 
>   tc filter add dev lo egress pref 1 matchall action vlan pop_eth continue
>   tc filter add dev lo egress pref 2 bpf da obj prog.o
>   # prog: bpf_skb_change_head(skb, 1, 0);
>   #       return bpf_redirect(veth1_ifindex, BPF_F_INGRESS);
>   # AF_PACKET SOCK_RAW on lo: eth / eth / 8192 bytes of payload
> 
>   kernel BUG at include/linux/skbuff.h:2839!
>   RIP: 0010:eth_type_trans (include/linux/etherdevice.h:635 net/ethernet/eth.c:163)
>   Call Trace:
>    __dev_forward_skb2 (net/core/dev.c:2507)
>    dev_forward_skb_nomtu (net/core/dev.c:2546)
>    __dev_queue_xmit (net/core/dev.c:4738 net/core/dev.c:4998)
>    packet_sendmsg (net/packet/af_packet.c:3157 net/packet/af_packet.c:3189)
> 
> Use eth_type_trans_careful(), and drop the packet if the Ethernet
> header can not be pulled. This also covers other dev_forward_skb()
> users (veth, macvlan, ipvlan, netdevsim, l2tp_eth).
> 
> Update the empty_skb BPF selftest: at lwt_xmit, BPF_PROG_TEST_RUN
> strips the Ethernet header, so the "veth ETH_HLEN+1" packet is a 1-byte
> skb. Redirecting it to veth ingress used to read the Ethernet header
> past skb->tail and deliver a 1-byte frame; it is now dropped with
> NET_RX_DROP, as veth_xmit() already does at egress.
> 
> Fixes: 3a0af8fd61f9 ("bpf: BPF for lightweight tunnel infrastructure")
> Signed-off-by: Eric Dumazet <edumazet@kernel.org>
> Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
> Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>

Reviewed-by: Willem de Bruijn <willemb@google.com>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH net v2 4/5] openvswitch: use eth_type_trans_careful() in internal_dev_recv()
  2026-10-28 12:27 ` [PATCH net v2 4/5] openvswitch: use eth_type_trans_careful() in internal_dev_recv() Eric Dumazet
@ 2026-10-28 19:04   ` Willem de Bruijn
  0 siblings, 0 replies; 12+ messages in thread
From: Willem de Bruijn @ 2026-10-28 19:04 UTC (permalink / raw)
  To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Eric Dumazet,
	Andrew Lunn, Aaron Conole, Eelco Chaudron, Ilya Maximets,
	Jamal Hadi Salim, Jiri Pirko, dev, Willem de Bruijn, Ren Wei

Eric Dumazet wrote:
> OVS actions like pop_eth followed by pop_mpls(ETH_P_TEB) or pop_nsh
> can expose an inner Ethernet header which is not in the linear part
> of the skb. Output to an internal port then crashes in eth_type_trans():
> 
>   flow: in_port(0),eth(),eth_type(0x8847),mpls(lse=0x00010140)
>   actions: pop_eth,pop_mpls(0x6558),0
>   # AF_PACKET SOCK_RAW on dp0: eth / mpls / eth / 4096 bytes of payload
> 
>   kernel BUG at include/linux/skbuff.h:2839!
>   RIP: 0010:eth_type_trans (include/linux/etherdevice.h:635 net/ethernet/eth.c:163)
>   Call Trace:
>    internal_dev_recv (net/openvswitch/vport-internal_dev.c:202) openvswitch
>    do_execute_actions (net/openvswitch/actions.c:1296) openvswitch
>    ovs_execute_actions (net/openvswitch/actions.c:1606) openvswitch
>    ovs_dp_process_packet (net/openvswitch/datapath.c:310) openvswitch
>    ovs_vport_receive (net/openvswitch/vport.c:448) openvswitch
>    internal_dev_xmit (net/openvswitch/vport-internal_dev.c:42) openvswitch
>    dev_hard_start_xmit (include/linux/netdevice.h:5455 include/linux/netdevice.h:5464 net/core/dev.c:4057 net/core/dev.c:4073)
>    __dev_queue_xmit (net/core/dev.c:5066)
>    packet_sendmsg (net/packet/af_packet.c:3157 net/packet/af_packet.c:3189)
> 
> Use eth_type_trans_careful(), and drop the packet if the Ethernet
> header can not be pulled. This covers all OVS actions at the consumer,
> instead of fixing each producer.
> 
> Fixes: b2d0f5d5dc53 ("openvswitch: enable NSH support")
> Fixes: f66b53fdbb22 ("openvswitch: New MPLS actions for layer 2 tunnelling")
> Signed-off-by: Eric Dumazet <edumazet@kernel.org>
> Reviewed-by: Aaron Conole <aconole@redhat.com>
> Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
> Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>

Reviewed-by: Willem de Bruijn <willemb@google.com>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack
  2026-10-28 17:34 ` [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Alexei Starovoitov
@ 2026-10-28 19:31   ` Daniel Borkmann
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Borkmann @ 2026-10-28 19:31 UTC (permalink / raw)
  To: Alexei Starovoitov, Eric Dumazet, David S . Miller,
	Jakub Kicinski, Paolo Abeni
  Cc: Willem de Bruijn, Simon Horman, netdev, bpf, Andrew Lunn,
	Aaron Conole, Eelco Chaudron, Ilya Maximets, Jamal Hadi Salim,
	Jiri Pirko, dev, Willem de Bruijn, Ren Wei

On 10/28/26 6:34 PM, Alexei Starovoitov wrote:
> On Wed, Oct 28, 2026 at 05:26 AM Eric Dumazet <edumazet@kernel.org> wrote:
>> Other eth_type_trans() users already pull the header or never see
>> such skbs:
> 
> netkit_xmit() has the same problem, I think.
> It calls eth_skb_pull_mac() directly, not eth_type_trans().
> It pulls ETH_HLEN before netkit_run(). The prog can shrink the linear
> part after that:
> 
>    AF_PACKET SOCK_RAW on nk0          eth (ETH_P_IP) / eth / 8192 bytes
>    tc egress on nk0
>      vlan pop_eth                     skb_headlen() == 0
>                                       skb_mac_header_len() == 0
>    netkit_xmit()
>      pskb_may_pull(skb, ETH_HLEN)     skb_headlen() == 14
>      netkit_run()
>        bpf_skb_adjust_room(skb, -1, BPF_ADJ_ROOM_MAC, 0)
>          bpf_skb_generic_pop()        off == 0, skb_headlen() == 13
>      eth_skb_pull_mac()               BUG() in __skb_pull()
> 
> It's an old bug and it doesn't block this series.
> It can be a follow up.
> 
> Something like this (compile tested only):
> 
> diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c
> index 82e608e..f093103 100644
> --- a/drivers/net/netkit.c
> +++ b/drivers/net/netkit.c
> @@ -116,6 +116,9 @@ static netdev_tx_t netkit_xmit(struct sk_buff *skb, struct net_device *dev)
>   	switch (ret) {
>   	case NETKIT_NEXT:
>   	case NETKIT_PASS:
> +		/* The prog may have shrunk the linear part */
> +		if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
> +			goto drop;
>   		eth_skb_pull_mac(skb);
>   		skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
>   		if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) {
Reproduced locally with a BPF selftest, and that fixes it. Feel free to
add my Acked-by.

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack
  2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
                   ` (5 preceding siblings ...)
  2026-10-28 17:34 ` [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Alexei Starovoitov
@ 2026-10-29 16:30 ` patchwork-bot+netdevbpf
  6 siblings, 0 replies; 12+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-10-29 16:30 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: davem, kuba, pabeni, willemb, horms, netdev, bpf, andrew+netdev,
	aconole, echaudro, i.maximets, jhs, jiri, dev,
	willemdebruijn.kernel, weir

Hello:

This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Wed, 28 Oct 2026 13:26:58 +0100 you wrote:
> eth_type_trans() assumes ETH_HLEN bytes are present in skb->head.
> NIC drivers always provide this, and they should keep using the fast
> version, without an extra pskb_may_pull().
> 
> Devices looping skbs from their transmit path back to their receive
> path get skbs built by the stack instead. tc actions (act_vlan pop_eth,
> act_ife decode), BPF helpers (bpf_skb_change_head() before a redirect)
> or OVS actions (pop_eth followed by pop_mpls/pop_nsh) can leave fewer
> than ETH_HLEN bytes in the linear part, and eth_type_trans() then hits
> the BUG() in __skb_pull().
> 
> [...]

Here is the summary with links:
  - [net,v2,1/5] net: add eth_type_trans_careful()
    https://git.kernel.org/netdev/net/c/2519a6fe7a8b
  - [net,v2,2/5] loopback: use eth_type_trans_careful()
    https://git.kernel.org/netdev/net/c/093a28998374
  - [net,v2,3/5] net: use eth_type_trans_careful() in __dev_forward_skb2()
    https://git.kernel.org/netdev/net/c/695e1408eb90
  - [net,v2,4/5] openvswitch: use eth_type_trans_careful() in internal_dev_recv()
    https://git.kernel.org/netdev/net/c/b55e5a0159c8
  - [net,v2,5/5] net/sched: act_ife: do not consume the inner header on egress
    https://git.kernel.org/netdev/net/c/498c631f9c6d

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-10-29 16:30 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-28 12:26 [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Eric Dumazet
2026-10-28 12:26 ` [PATCH net v2 1/5] net: add eth_type_trans_careful() Eric Dumazet
2026-10-28 12:27 ` [PATCH net v2 2/5] loopback: use eth_type_trans_careful() Eric Dumazet
2026-10-28 18:48   ` Willem de Bruijn
2026-10-28 12:27 ` [PATCH net v2 3/5] net: use eth_type_trans_careful() in __dev_forward_skb2() Eric Dumazet
2026-10-28 19:03   ` Willem de Bruijn
2026-10-28 12:27 ` [PATCH net v2 4/5] openvswitch: use eth_type_trans_careful() in internal_dev_recv() Eric Dumazet
2026-10-28 19:04   ` Willem de Bruijn
2026-10-28 12:27 ` [PATCH net v2 5/5] net/sched: act_ife: do not consume the inner header on egress Eric Dumazet
2026-10-28 17:34 ` [PATCH net v2 0/5] net: fix eth_type_trans() crashes on skbs coming from the stack Alexei Starovoitov
2026-10-28 19:31   ` Daniel Borkmann
2026-10-29 16:30 ` patchwork-bot+netdevbpf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.