From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefano Brivio Subject: Re: [PATCH net] fou, fou6: do not assume linear skbs Date: Fri, 11 Jan 2019 15:15:07 +0100 Message-ID: <20190111151507.393bab41@redhat.com> References: <20190111125552.148871-1-edumazet@google.com> Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Cc: "David S . Miller" , netdev , Eric Dumazet , syzbot , Sabrina Dubroca To: Eric Dumazet Return-path: Received: from mx1.redhat.com ([209.132.183.28]:42470 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733258AbfAKOPP (ORCPT ); Fri, 11 Jan 2019 09:15:15 -0500 In-Reply-To: <20190111125552.148871-1-edumazet@google.com> Sender: netdev-owner@vger.kernel.org List-ID: On Fri, 11 Jan 2019 04:55:52 -0800 Eric Dumazet wrote: > Both gue_err() and gue6_err() incorrectly assume > linear skbs. Fix them to use pskb_may_pull(). Thanks for fixing this! I stupidly didn't suspect we could get non-linear skbs there. Just two things: > +++ b/net/ipv4/fou.c > @@ -1020,10 +1020,11 @@ static int gue_err(struct sk_buff *skb, u32 info) > { > int transport_offset = skb_transport_offset(skb); > struct guehdr *guehdr; > - size_t optlen; > + size_t len, optlen; > int ret; > > - if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) > + len = sizeof(struct udphdr) + sizeof(struct guehdr); > + if (!pskb_may_pull(skb, len)) > return -EINVAL; > > guehdr = (struct guehdr *)&udp_hdr(skb)[1]; > @@ -1058,6 +1059,10 @@ static int gue_err(struct sk_buff *skb, u32 info) > > optlen = guehdr->hlen << 2; > > + if (!pskb_may_pull(skb, len + optlen) ^ ) missing > + return -EINVAL; > + > + guehdr = (struct guehdr *)&udp_hdr(skb)[1]; > if (validate_gue_flags(guehdr, optlen)) > return -EINVAL; > > diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c > index 7da7bf3b7fe3953eeb60addfffd6687c4da582c4..320413af4890641e7199d7d7102e7d8c2794d557 100644 > --- a/net/ipv6/fou6.c > +++ b/net/ipv6/fou6.c > @@ -90,10 +90,11 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, > { > int transport_offset = skb_transport_offset(skb); > struct guehdr *guehdr; > - size_t optlen; > + size_t len, optlen; > int ret; > > - if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) > + len = sizeof(struct udphdr) + sizeof(struct guehdr); > + if (!pskb_may_pull(skb, len)) > return -EINVAL; > > guehdr = (struct guehdr *)&udp_hdr(skb)[1]; > @@ -128,6 +129,10 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, > > optlen = guehdr->hlen << 2; > > + if (!pskb_may_pull(skb, len + optlen) ^ ) missing > + return -EINVAL; > + > + guehdr = (struct guehdr *)&udp_hdr(skb)[1]; > if (validate_gue_flags(guehdr, optlen)) > return -EINVAL; > -- Stefano