diff options
-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 757c9171e7c2..ab996f9c0fe0 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -352,13 +352,24 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | |||
352 | skb->ip_summed = CHECKSUM_NONE; | 352 | skb->ip_summed = CHECKSUM_NONE; |
353 | 353 | ||
354 | skb->transport_header = skb->network_header; | 354 | skb->transport_header = skb->network_header; |
355 | err = memcpy_fromiovecend((void *)iph, from, 0, length); | 355 | err = -EFAULT; |
356 | if (err) | 356 | if (memcpy_fromiovecend((void *)iph, from, 0, length)) |
357 | goto error_fault; | 357 | goto error_free; |
358 | 358 | ||
359 | /* We don't modify invalid header */ | ||
360 | iphlen = iph->ihl * 4; | 359 | iphlen = iph->ihl * 4; |
361 | if (iphlen >= sizeof(*iph) && iphlen <= length) { | 360 | |
361 | /* | ||
362 | * We don't want to modify the ip header, but we do need to | ||
363 | * be sure that it won't cause problems later along the network | ||
364 | * stack. Specifically we want to make sure that iph->ihl is a | ||
365 | * sane value. If ihl points beyond the length of the buffer passed | ||
366 | * in, reject the frame as invalid | ||
367 | */ | ||
368 | err = -EINVAL; | ||
369 | if (iphlen > length) | ||
370 | goto error_free; | ||
371 | |||
372 | if (iphlen >= sizeof(*iph)) { | ||
362 | if (!iph->saddr) | 373 | if (!iph->saddr) |
363 | iph->saddr = rt->rt_src; | 374 | iph->saddr = rt->rt_src; |
364 | iph->check = 0; | 375 | iph->check = 0; |
@@ -381,8 +392,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | |||
381 | out: | 392 | out: |
382 | return 0; | 393 | return 0; |
383 | 394 | ||
384 | error_fault: | 395 | error_free: |
385 | err = -EFAULT; | ||
386 | kfree_skb(skb); | 396 | kfree_skb(skb); |
387 | error: | 397 | error: |
388 | IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); | 398 | IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); |