diff options
Diffstat (limited to 'net/ipv4/raw.c')
| -rw-r--r-- | net/ipv4/raw.c | 24 | 
1 files changed, 17 insertions, 7 deletions
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 9ef8c0829a7..ce154b47f1d 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -351,13 +351,24 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,  	skb->ip_summed = CHECKSUM_NONE;  	skb->transport_header = skb->network_header; -	err = memcpy_fromiovecend((void *)iph, from, 0, length); -	if (err) -		goto error_fault; +	err = -EFAULT; +	if (memcpy_fromiovecend((void *)iph, from, 0, length)) +		goto error_free; -	/* We don't modify invalid header */  	iphlen = iph->ihl * 4; -	if (iphlen >= sizeof(*iph) && iphlen <= length) { + +	/* +	 * We don't want to modify the ip header, but we do need to +	 * be sure that it won't cause problems later along the network +	 * stack.  Specifically we want to make sure that iph->ihl is a +	 * sane value.  If ihl points beyond the length of the buffer passed +	 * in, reject the frame as invalid +	 */ +	err = -EINVAL; +	if (iphlen > length) +		goto error_free; + +	if (iphlen >= sizeof(*iph)) {  		if (!iph->saddr)  			iph->saddr = rt->rt_src;  		iph->check   = 0; @@ -380,8 +391,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,  out:  	return 0; -error_fault: -	err = -EFAULT; +error_free:  	kfree_skb(skb);  error:  	IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);  |