lkml.org 
[lkml]   [2017]   [Mar]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 354/370] ipv6: fix ip6_tnl_parse_tlv_enc_lim()
    3.16.42-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Eric Dumazet <edumazet@google.com>

    [ Upstream commit fbfa743a9d2a0ffa24251764f10afc13eb21e739 ]

    This function suffers from multiple issues.

    First one is that pskb_may_pull() may reallocate skb->head,
    so the 'raw' pointer needs either to be reloaded or not used at all.

    Second issue is that NEXTHDR_DEST handling does not validate
    that the options are present in skb->data, so we might read
    garbage or access non existent memory.

    With help from Willem de Bruijn.

    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Reported-by: Dmitry Vyukov <dvyukov@google.com>
    Cc: Willem de Bruijn <willemb@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    net/ipv6/ip6_tunnel.c | 34 ++++++++++++++++++++++------------
    1 file changed, 22 insertions(+), 12 deletions(-)

    --- a/net/ipv6/ip6_tunnel.c
    +++ b/net/ipv6/ip6_tunnel.c
    @@ -402,18 +402,19 @@ ip6_tnl_dev_uninit(struct net_device *de

    __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
    {
    - const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
    - __u8 nexthdr = ipv6h->nexthdr;
    - __u16 off = sizeof (*ipv6h);
    + const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
    + unsigned int nhoff = raw - skb->data;
    + unsigned int off = nhoff + sizeof(*ipv6h);
    + u8 next, nexthdr = ipv6h->nexthdr;

    while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
    - __u16 optlen = 0;
    struct ipv6_opt_hdr *hdr;
    - if (raw + off + sizeof (*hdr) > skb->data &&
    - !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
    + u16 optlen;
    +
    + if (!pskb_may_pull(skb, off + sizeof(*hdr)))
    break;

    - hdr = (struct ipv6_opt_hdr *) (raw + off);
    + hdr = (struct ipv6_opt_hdr *)(skb->data + off);
    if (nexthdr == NEXTHDR_FRAGMENT) {
    struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
    if (frag_hdr->frag_off)
    @@ -424,20 +425,29 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct s
    } else {
    optlen = ipv6_optlen(hdr);
    }
    + /* cache hdr->nexthdr, since pskb_may_pull() might
    + * invalidate hdr
    + */
    + next = hdr->nexthdr;
    if (nexthdr == NEXTHDR_DEST) {
    - __u16 i = off + 2;
    + u16 i = 2;
    +
    + /* Remember : hdr is no longer valid at this point. */
    + if (!pskb_may_pull(skb, off + optlen))
    + break;
    +
    while (1) {
    struct ipv6_tlv_tnl_enc_lim *tel;

    /* No more room for encapsulation limit */
    - if (i + sizeof (*tel) > off + optlen)
    + if (i + sizeof(*tel) > optlen)
    break;

    - tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
    + tel = (struct ipv6_tlv_tnl_enc_lim *) skb->data + off + i;
    /* return index of option if found and valid */
    if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
    tel->length == 1)
    - return i;
    + return i + off - nhoff;
    /* else jump to next option */
    if (tel->type)
    i += tel->length + 2;
    @@ -445,7 +455,7 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct s
    i++;
    }
    }
    - nexthdr = hdr->nexthdr;
    + nexthdr = next;
    off += optlen;
    }
    return 0;
    \
     
     \ /
      Last update: 2017-03-10 14:20    [W:4.007 / U:0.148 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site