diff options
author | Guillaume Nault <gnault@redhat.com> | 2021-08-06 17:52:06 +0200 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2021-08-09 15:37:43 -0700 |
commit | 143a8526ab5fd4f8a0c4fe2a9cb28c181dc5a95f (patch) | |
tree | 9d2766c631ccc95b0ddd4103e80dbe46f1cf9e66 | |
parent | d6e712aa7e6a3d5a9633f4bcbe2237f3edc292bd (diff) | |
download | linux-143a8526ab5fd4f8a0c4fe2a9cb28c181dc5a95f.tar.bz2 |
bareudp: Fix invalid read beyond skb's linear data
Data beyond the UDP header might not be part of the skb's linear data.
Use skb_copy_bits() instead of direct access to skb->data+X, so that
we read the correct bytes even on a fragmented skb.
Fixes: 4b5f67232d95 ("net: Special handling for IP & MPLS.")
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Link: https://lore.kernel.org/r/7741c46545c6ef02e70c80a9b32814b22d9616b3.1628264975.git.gnault@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | drivers/net/bareudp.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index a7ee0af1af90..54e321a695ce 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -71,12 +71,18 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) family = AF_INET6; if (bareudp->ethertype == htons(ETH_P_IP)) { - struct iphdr *iphdr; + __u8 ipversion; - iphdr = (struct iphdr *)(skb->data + BAREUDP_BASE_HLEN); - if (iphdr->version == 4) { - proto = bareudp->ethertype; - } else if (bareudp->multi_proto_mode && (iphdr->version == 6)) { + if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion, + sizeof(ipversion))) { + bareudp->dev->stats.rx_dropped++; + goto drop; + } + ipversion >>= 4; + + if (ipversion == 4) { + proto = htons(ETH_P_IP); + } else if (ipversion == 6 && bareudp->multi_proto_mode) { proto = htons(ETH_P_IPV6); } else { bareudp->dev->stats.rx_dropped++; |