Commit 0d4f0608619de59fd8169dd8e72aadc28d80e715

Authored by Eric Dumazet
Committed by David S. Miller
1 parent b009aac12c

tcp: dont handle MTU reduction on LISTEN socket

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>

Showing 2 changed files with 14 additions and 7 deletions Side-by-side Diff

... ... @@ -274,13 +274,6 @@
274 274 struct inet_sock *inet = inet_sk(sk);
275 275 u32 mtu = tcp_sk(sk)->mtu_info;
276 276  
277   - /* We are not interested in TCP_LISTEN and open_requests (SYN-ACKs
278   - * send out by Linux are always <576bytes so they should go through
279   - * unfragmented).
280   - */
281   - if (sk->sk_state == TCP_LISTEN)
282   - return;
283   -
284 277 dst = inet_csk_update_pmtu(sk, mtu);
285 278 if (!dst)
286 279 return;
... ... @@ -408,6 +401,13 @@
408 401 goto out;
409 402  
410 403 if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
  404 + /* We are not interested in TCP_LISTEN and open_requests
  405 + * (SYN-ACKs send out by Linux are always <576bytes so
  406 + * they should go through unfragmented).
  407 + */
  408 + if (sk->sk_state == TCP_LISTEN)
  409 + goto out;
  410 +
411 411 tp->mtu_info = info;
412 412 if (!sock_owned_by_user(sk)) {
413 413 tcp_v4_mtu_reduced(sk);
... ... @@ -389,6 +389,13 @@
389 389 }
390 390  
391 391 if (type == ICMPV6_PKT_TOOBIG) {
  392 + /* We are not interested in TCP_LISTEN and open_requests
  393 + * (SYN-ACKs send out by Linux are always <576bytes so
  394 + * they should go through unfragmented).
  395 + */
  396 + if (sk->sk_state == TCP_LISTEN)
  397 + goto out;
  398 +
392 399 tp->mtu_info = ntohl(info);
393 400 if (!sock_owned_by_user(sk))
394 401 tcp_v6_mtu_reduced(sk);