mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ipv6/exthdrs: strict Pad1 and PadN check
The following tightens the padding check from commit
c1412fce7e :
* 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>
			
			
This commit is contained in:
		
							parent
							
								
									f7142e6c22
								
							
						
					
					
						commit
						9b905fe684
					
				
					 1 changed files with 14 additions and 1 deletions
				
			
		| 
						 | 
					@ -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)
 | 
				
			||||||
		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)
 | 
				
			||||||
			 * 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)
 | 
				
			||||||
				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:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue