|
@@ -352,13 +352,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;
|
|
@@ -381,8 +392,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);
|