net: fix sk_forward_alloc corruptions
[pandora-kernel.git] / net / ipv6 / udp.c
index 2850e35..3048f90 100644 (file)
@@ -328,6 +328,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        int err;
        int is_udplite = IS_UDPLITE(sk);
        int is_udp4;
+       bool slow;
 
        if (addr_len)
                *addr_len=sizeof(struct sockaddr_in6);
@@ -424,7 +425,7 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock(sk);
+       slow = lock_sock_fast(sk);
        if (!skb_kill_datagram(sk, skb, flags)) {
                if (is_udp4)
                        UDP_INC_STATS_USER(sock_net(sk),
@@ -433,7 +434,7 @@ csum_copy_err:
                        UDP6_INC_STATS_USER(sock_net(sk),
                                        UDP_MIB_INERRORS, is_udplite);
        }
-       release_sock(sk);
+       unlock_sock_fast(sk, slow);
 
        if (flags & MSG_DONTWAIT)
                return -EAGAIN;
@@ -465,9 +466,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (sk->sk_state != TCP_ESTABLISHED && !np->recverr)
                goto out;
 
-       if (np->recverr)
+       if (np->recverr) {
+               bh_lock_sock(sk);
                ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
-
+               bh_unlock_sock(sk);
+       }
        sk->sk_err = err;
        sk->sk_error_report(sk);
 out:
@@ -514,7 +517,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
                        goto drop;
        }
 
-       if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
+       if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
                /* Note that an ENOMEM error is charged twice */
                if (rc == -ENOMEM)
                        UDP6_INC_STATS_BH(sock_net(sk),
@@ -584,6 +587,10 @@ static void flush_stack(struct sock **stack, unsigned int count,
 
                sk = stack[i];
                if (skb1) {
+                       if (sk_rcvqueues_full(sk, skb)) {
+                               kfree_skb(skb1);
+                               goto drop;
+                       }
                        bh_lock_sock(sk);
                        if (!sock_owned_by_user(sk))
                                udpv6_queue_rcv_skb(sk, skb1);
@@ -695,7 +702,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        u32 ulen = 0;
 
        if (!pskb_may_pull(skb, sizeof(struct udphdr)))
-               goto short_packet;
+               goto discard;
 
        saddr = &ipv6_hdr(skb)->saddr;
        daddr = &ipv6_hdr(skb)->daddr;
@@ -759,6 +766,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
 
        /* deliver */
 
+       if (sk_rcvqueues_full(sk, skb)) {
+               sock_put(sk);
+               goto discard;
+       }
        bh_lock_sock(sk);
        if (!sock_owned_by_user(sk))
                udpv6_queue_rcv_skb(sk, skb);
@@ -773,9 +784,14 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        return 0;
 
 short_packet:
-       LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n",
+       LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n",
                       proto == IPPROTO_UDPLITE ? "-Lite" : "",
-                      ulen, skb->len);
+                      saddr,
+                      ntohs(uh->source),
+                      ulen,
+                      skb->len,
+                      daddr,
+                      ntohs(uh->dest));
 
 discard:
        UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);