summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Nault <gnault@redhat.com>2024-09-11 11:20:58 +0200
committerJakub Kicinski <kuba@kernel.org>2024-09-12 20:30:15 -0700
commit45fa29c85117170b0508790f878b13ec6593c888 (patch)
tree1b73c1137695a9d5da5ead2176aef124918f7c44
parent5abfdfd402699ce7c1e81d1a25bc37f60f7741ff (diff)
downloadlinux-45fa29c85117170b0508790f878b13ec6593c888.tar.gz
linux-45fa29c85117170b0508790f878b13ec6593c888.tar.bz2
linux-45fa29c85117170b0508790f878b13ec6593c888.zip
bareudp: Pull inner IP header in bareudp_udp_encap_recv().
Bareudp reads the inner IP header to get the ECN value. Therefore, it needs to ensure that it's part of the skb's linear data. This is similar to the vxlan and geneve fixes for that same problem: * commit f7789419137b ("vxlan: Pull inner IP header in vxlan_rcv().") * commit 1ca1ba465e55 ("geneve: make sure to pull inner header in geneve_rx()") Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") Signed-off-by: Guillaume Nault <gnault@redhat.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/5205940067c40218a70fbb888080466b2fc288db.1726046181.git.gnault@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/bareudp.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index 7aca0544fb29..b4e820a123ca 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -68,6 +68,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
__be16 proto;
void *oiph;
int err;
+ int nh;
bareudp = rcu_dereference_sk_user_data(sk);
if (!bareudp)
@@ -148,10 +149,25 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
}
skb_dst_set(skb, &tun_dst->dst);
skb->dev = bareudp->dev;
- oiph = skb_network_header(skb);
- skb_reset_network_header(skb);
skb_reset_mac_header(skb);
+ /* Save offset of outer header relative to skb->head,
+ * because we are going to reset the network header to the inner header
+ * and might change skb->head.
+ */
+ nh = skb_network_header(skb) - skb->head;
+
+ skb_reset_network_header(skb);
+
+ if (!pskb_inet_may_pull(skb)) {
+ DEV_STATS_INC(bareudp->dev, rx_length_errors);
+ DEV_STATS_INC(bareudp->dev, rx_errors);
+ goto drop;
+ }
+
+ /* Get the outer header. */
+ oiph = skb->head + nh;
+
if (!ipv6_mod_enabled() || family == AF_INET)
err = IP_ECN_decapsulate(oiph, skb);
else