Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv6: mip6: fix mip6_mh_filter()

mip6_mh_filter() should not modify its input, or else its caller
would need to recompute ipv6_hdr() if skb->head is reallocated.

Use skb_header_pointer() instead of pskb_may_pull()

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
96af69ea 78cc88c4

+11 -9
+11 -9
net/ipv6/mip6.c
··· 86 86 87 87 static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) 88 88 { 89 - struct ip6_mh *mh; 89 + struct ip6_mh _hdr; 90 + const struct ip6_mh *mh; 90 91 91 - if (!pskb_may_pull(skb, (skb_transport_offset(skb)) + 8) || 92 - !pskb_may_pull(skb, (skb_transport_offset(skb) + 93 - ((skb_transport_header(skb)[1] + 1) << 3)))) 92 + mh = skb_header_pointer(skb, skb_transport_offset(skb), 93 + sizeof(_hdr), &_hdr); 94 + if (!mh) 94 95 return -1; 95 96 96 - mh = (struct ip6_mh *)skb_transport_header(skb); 97 + if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len) 98 + return -1; 97 99 98 100 if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) { 99 101 LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n", 100 102 mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type)); 101 - mip6_param_prob(skb, 0, ((&mh->ip6mh_hdrlen) - 102 - skb_network_header(skb))); 103 + mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) + 104 + skb_network_header_len(skb)); 103 105 return -1; 104 106 } 105 107 106 108 if (mh->ip6mh_proto != IPPROTO_NONE) { 107 109 LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n", 108 110 mh->ip6mh_proto); 109 - mip6_param_prob(skb, 0, ((&mh->ip6mh_proto) - 110 - skb_network_header(skb))); 111 + mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) + 112 + skb_network_header_len(skb)); 111 113 return -1; 112 114 } 113 115