Commit 9b905fe6 authored by Eldad Zack's avatar Eldad Zack Committed by David S. Miller

ipv6/exthdrs: strict Pad1 and PadN check

The following tightens the padding check from commit
c1412fce :

* Take into account combinations of consecutive Pad1 and PadN.

* Catch the corner case of when only padding is present in the
  header, when the extention header length is 0 (i.e., 8 bytes).
  In this case, the header would have exactly 6 bytes of padding:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:  Next Header  : Hdr Ext Len=0 :                               :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
:                        Padding (Pad1 or PadN)                 :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Signed-off-by: default avatarEldad Zack <eldad@fogrefinery.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f7142e6c
...@@ -144,6 +144,7 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb) ...@@ -144,6 +144,7 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
const unsigned char *nh = skb_network_header(skb); const unsigned char *nh = skb_network_header(skb);
int off = skb_network_header_len(skb); int off = skb_network_header_len(skb);
int len = (skb_transport_header(skb)[1] + 1) << 3; int len = (skb_transport_header(skb)[1] + 1) << 3;
int padlen = 0;
if (skb_transport_offset(skb) + len > skb_headlen(skb)) if (skb_transport_offset(skb) + len > skb_headlen(skb))
goto bad; goto bad;
...@@ -158,6 +159,9 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb) ...@@ -158,6 +159,9 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
switch (nh[off]) { switch (nh[off]) {
case IPV6_TLV_PAD1: case IPV6_TLV_PAD1:
optlen = 1; optlen = 1;
padlen++;
if (padlen > 7)
goto bad;
break; break;
case IPV6_TLV_PADN: case IPV6_TLV_PADN:
...@@ -166,7 +170,8 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb) ...@@ -166,7 +170,8 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
* of 8. 7 is therefore the highest valid value. * of 8. 7 is therefore the highest valid value.
* See also RFC 4942, Section 2.1.9.5. * See also RFC 4942, Section 2.1.9.5.
*/ */
if (optlen > 7) padlen += optlen;
if (padlen > 7)
goto bad; goto bad;
/* RFC 4942 recommends receiving hosts to /* RFC 4942 recommends receiving hosts to
* actively check PadN payload to contain * actively check PadN payload to contain
...@@ -195,11 +200,19 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb) ...@@ -195,11 +200,19 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
if (ip6_tlvopt_unknown(skb, off) == 0) if (ip6_tlvopt_unknown(skb, off) == 0)
return false; return false;
} }
padlen = 0;
break; break;
} }
off += optlen; off += optlen;
len -= optlen; len -= optlen;
} }
/* This case will not be caught by above check since its padding
* length is smaller than 7:
* 1 byte NH + 1 byte Length + 6 bytes Padding
*/
if ((padlen == 6) && ((off - skb_network_header_len(skb)) == 8))
goto bad;
if (len == 0) if (len == 0)
return true; return true;
bad: bad:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment