lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Sun, 26 Apr 2020 19:10:02 -0600
From:   "Jason A. Donenfeld" <Jason@...c4.com>
To:     netdev@...r.kernel.org
Cc:     "Jason A. Donenfeld" <Jason@...c4.com>,
        Toke Høiland-Jørgensen <toke@...hat.com>
Subject: [PATCH RFC v1] net: xdp: allow for layer 3 packets in generic skb handler

A user reported a few days ago that packets from wireguard were possibly
ignored by XDP [1]. We haven't heard back from the original reporter to
receive more info, so this here is mostly speculative. Successfully nerd
sniped, Toke and I started poking around. Toke noticed that the generic
skb xdp handler path seems to assume that packets will always have an
ethernet header, which really isn't always the case for layer 3 packets,
which are produced by multiple drivers. This patch is untested, but I
wanted to gauge interest in this approach: if the mac_len is 0, then we
assume that it's a layer 3 packet, and figure out skb->protocol from
looking at the IP header. This patch also adds some stricter testing
around mac_len before we assume that it's an ethhdr.

[1] https://lore.kernel.org/wireguard/M5WzVK5--3-2@tuta.io/

Cc: Toke Høiland-Jørgensen <toke@...hat.com>
Signed-off-by: Jason A. Donenfeld <Jason@...c4.com>
---
 net/core/dev.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 522288177bbd..1c4b0af09be2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4551,9 +4551,11 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
 	xdp->data_hard_start = skb->data - skb_headroom(skb);
 	orig_data_end = xdp->data_end;
 	orig_data = xdp->data;
-	eth = (struct ethhdr *)xdp->data;
-	orig_bcast = is_multicast_ether_addr_64bits(eth->h_dest);
-	orig_eth_type = eth->h_proto;
+	if (mac_len == sizeof(struct ethhdr)) {
+		eth = (struct ethhdr *)xdp->data;
+		orig_bcast = is_multicast_ether_addr_64bits(eth->h_dest);
+		orig_eth_type = eth->h_proto;
+	}
 
 	rxqueue = netif_get_rxqueue(skb);
 	xdp->rxq = &rxqueue->xdp_rxq;
@@ -4583,11 +4585,24 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
 	}
 
 	/* check if XDP changed eth hdr such SKB needs update */
-	eth = (struct ethhdr *)xdp->data;
-	if ((orig_eth_type != eth->h_proto) ||
-	    (orig_bcast != is_multicast_ether_addr_64bits(eth->h_dest))) {
-		__skb_push(skb, ETH_HLEN);
-		skb->protocol = eth_type_trans(skb, skb->dev);
+	if (mac_len == 0) {
+		switch (ip_hdr(skb)->version) {
+		case 4:
+			skb->protocol = htons(ETH_P_IP);
+			break;
+		case 6:
+			skb->protocol = htons(ETH_P_IPV6);
+			break;
+		default:
+			goto do_drop;
+		}
+	} else if (mac_len == sizeof(struct ethhdr)) {
+		eth = (struct ethhdr *)xdp->data;
+		if ((orig_eth_type != eth->h_proto) ||
+		    (orig_bcast != is_multicast_ether_addr_64bits(eth->h_dest))) {
+			__skb_push(skb, ETH_HLEN);
+			skb->protocol = eth_type_trans(skb, skb->dev);
+		}
 	}
 
 	switch (act) {
-- 
2.26.2

Powered by blists - more mailing lists