[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <c83f8777-f6be-029b-980d-9f974b4e28ce@gmail.com>
Date: Thu, 30 May 2019 10:17:04 -0700
From: Eric Dumazet <eric.dumazet@...il.com>
To: Young Xiao <92siuyang@...il.com>, davem@...emloft.net,
kuznet@....inr.ac.ru, yoshfuji@...ux-ipv6.org,
netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
Steffen Klassert <steffen.klassert@...unet.com>,
Herbert Xu <herbert@...dor.apana.org.au>
Subject: Re: [PATCH] ipv6: Prevent overrun when parsing v6 header options
On 5/30/19 8:28 AM, Young Xiao wrote:
> The fragmentation code tries to parse the header options in order
> to figure out where to insert the fragment option. Since nexthdr points
> to an invalid option, the calculation of the size of the network header
> can made to be much larger than the linear section of the skb and data
> is read outside of it.
>
> This vulnerability is similar to CVE-2017-9074.
>
> Signed-off-by: Young Xiao <92siuyang@...il.com>
> ---
> net/ipv6/mip6.c | 24 ++++++++++++++----------
> 1 file changed, 14 insertions(+), 10 deletions(-)
>
> diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
> index 64f0f7b..30ed1c5 100644
> --- a/net/ipv6/mip6.c
> +++ b/net/ipv6/mip6.c
> @@ -263,8 +263,6 @@ static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
> u8 **nexthdr)
> {
> u16 offset = sizeof(struct ipv6hdr);
> - struct ipv6_opt_hdr *exthdr =
> - (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
> const unsigned char *nh = skb_network_header(skb);
> unsigned int packet_len = skb_tail_pointer(skb) -
> skb_network_header(skb);
> @@ -272,7 +270,8 @@ static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
>
> *nexthdr = &ipv6_hdr(skb)->nexthdr;
>
> - while (offset + 1 <= packet_len) {
> + while (offset <= packet_len) {
> + struct ipv6_opt_hdr *exthdr;
>
> switch (**nexthdr) {
> case NEXTHDR_HOP:
> @@ -299,12 +298,15 @@ static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
> return offset;
> }
>
> + if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
> + return -EINVAL;
> +
> + exthdr = (struct ipv6_opt_hdr *)(nh + offset);
> offset += ipv6_optlen(exthdr);
> *nexthdr = &exthdr->nexthdr;
> - exthdr = (struct ipv6_opt_hdr *)(nh + offset);
> }
>
> - return offset;
> + return -EINVAL;
> }
>
Ok, but have you checked that callers have been fixed ?
xfrm6_transport_output() seems buggy as well,
unless the skbs are linearized before entering these functions ?
Thanks.
Powered by blists - more mailing lists