When an ICMP ICMP_FRAG_NEEDED (or ICMPV6_PKT_TOOBIG) message finds a
LISTEN socket, and this socket is currently owned by the user, we
set TCP_MTU_REDUCED_DEFERRED flag in listener tsq_flags.
This is bad because if we clone the parent before it had a chance to
clear the flag, the child inherits the tsq_flags value, and next
tcp_release_cb() on the child will decrement sk_refcnt.
Result is that we might free a live TCP socket, as reported by
Dormando.
IPv4: Attempt to release TCP socket in state 1
Fix this issue by testing sk_state against TCP_LISTEN early, so that we
set TCP_MTU_REDUCED_DEFERRED on appropriate sockets (not a LISTEN one)
This bug was introduced in commit 
563d34d05786
(tcp: dont drop MTU reduction indications)
Reported-by: dormando <dormando@rydia.net>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
        struct inet_sock *inet = inet_sk(sk);
        u32 mtu = tcp_sk(sk)->mtu_info;
 
-       /* We are not interested in TCP_LISTEN and open_requests (SYN-ACKs
-        * send out by Linux are always <576bytes so they should go through
-        * unfragmented).
-        */
-       if (sk->sk_state == TCP_LISTEN)
-               return;
-
        dst = inet_csk_update_pmtu(sk, mtu);
        if (!dst)
                return;
                        goto out;
 
                if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
+                       /* We are not interested in TCP_LISTEN and open_requests
+                        * (SYN-ACKs send out by Linux are always <576bytes so
+                        * they should go through unfragmented).
+                        */
+                       if (sk->sk_state == TCP_LISTEN)
+                               goto out;
+
                        tp->mtu_info = info;
                        if (!sock_owned_by_user(sk)) {
                                tcp_v4_mtu_reduced(sk);
 
        }
 
        if (type == ICMPV6_PKT_TOOBIG) {
+               /* We are not interested in TCP_LISTEN and open_requests
+                * (SYN-ACKs send out by Linux are always <576bytes so
+                * they should go through unfragmented).
+                */
+               if (sk->sk_state == TCP_LISTEN)
+                       goto out;
+
                tp->mtu_info = ntohl(info);
                if (!sock_owned_by_user(sk))
                        tcp_v6_mtu_reduced(sk);