aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEldad Zack <eldad@fogrefinery.com>2012-05-19 21:59:33 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-20 16:58:39 -0400
commit9b905fe68433378032b851c4d81a59187689fa52 (patch)
tree307801197cf9ce8b520a026962bf1e73f0019f9f /net
parentf7142e6c226076fd40c2ebaad9fb0c9a631b790e (diff)
ipv6/exthdrs: strict Pad1 and PadN check
The following tightens the padding check from commit c1412fce7eccae62b4de22494f6ab3ff8a90c0c6 : * 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: Eldad Zack <eldad@fogrefinery.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/exthdrs.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 50ec95f9aeeb..6447dc49429f 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -144,6 +144,7 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
144 const unsigned char *nh = skb_network_header(skb); 144 const unsigned char *nh = skb_network_header(skb);
145 int off = skb_network_header_len(skb); 145 int off = skb_network_header_len(skb);
146 int len = (skb_transport_header(skb)[1] + 1) << 3; 146 int len = (skb_transport_header(skb)[1] + 1) << 3;
147 int padlen = 0;
147 148
148 if (skb_transport_offset(skb) + len > skb_headlen(skb)) 149 if (skb_transport_offset(skb) + len > skb_headlen(skb))
149 goto bad; 150 goto bad;
@@ -158,6 +159,9 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
158 switch (nh[off]) { 159 switch (nh[off]) {
159 case IPV6_TLV_PAD1: 160 case IPV6_TLV_PAD1:
160 optlen = 1; 161 optlen = 1;
162 padlen++;
163 if (padlen > 7)
164 goto bad;
161 break; 165 break;
162 166
163 case IPV6_TLV_PADN: 167 case IPV6_TLV_PADN:
@@ -166,7 +170,8 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
166 * of 8. 7 is therefore the highest valid value. 170 * of 8. 7 is therefore the highest valid value.
167 * See also RFC 4942, Section 2.1.9.5. 171 * See also RFC 4942, Section 2.1.9.5.
168 */ 172 */
169 if (optlen > 7) 173 padlen += optlen;
174 if (padlen > 7)
170 goto bad; 175 goto bad;
171 /* RFC 4942 recommends receiving hosts to 176 /* RFC 4942 recommends receiving hosts to
172 * actively check PadN payload to contain 177 * 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 if (ip6_tlvopt_unknown(skb, off) == 0) 200 if (ip6_tlvopt_unknown(skb, off) == 0)
196 return false; 201 return false;
197 } 202 }
203 padlen = 0;
198 break; 204 break;
199 } 205 }
200 off += optlen; 206 off += optlen;
201 len -= optlen; 207 len -= optlen;
202 } 208 }
209 /* This case will not be caught by above check since its padding
210 * length is smaller than 7:
211 * 1 byte NH + 1 byte Length + 6 bytes Padding
212 */
213 if ((padlen == 6) && ((off - skb_network_header_len(skb)) == 8))
214 goto bad;
215
203 if (len == 0) 216 if (len == 0)
204 return true; 217 return true;
205bad: 218bad: