)]}'
{
  "commit": "565b7b2d2e632b5792879c0c9cccdd9eecd31195",
  "tree": "f5bbe0e7a2719f6076a567cb3a68ff47f0c4bcb9",
  "parents": [
    "7a938f80264f2cbfb0c0841b450eab42a8093281"
  ],
  "author": {
    "name": "Konstantin Khorenko",
    "email": "khorenko@openvz.org",
    "time": "Thu Jun 24 21:54:58 2010 -0700"
  },
  "committer": {
    "name": "David S. Miller",
    "email": "davem@davemloft.net",
    "time": "Thu Jun 24 21:54:58 2010 -0700"
  },
  "message": "tcp: do not send reset to already closed sockets\n\ni\u0027ve found that tcp_close() can be called for an already closed\nsocket, but still sends reset in this case (tcp_send_active_reset())\nwhich seems to be incorrect.  Moreover, a packet with reset is sent\nwith different source port as original port number has been already\ncleared on socket.  Besides that incrementing stat counter for\nLINUX_MIB_TCPABORTONCLOSE also does not look correct in this case.\n\nInitially this issue was found on 2.6.18-x RHEL5 kernel, but the same\nseems to be true for the current mainstream kernel (checked on\n2.6.35-rc3).  Please, correct me if i missed something.\n\nHow that happens:\n\n1) the server receives a packet for socket in TCP_CLOSE_WAIT state\n   that triggers a tcp_reset():\n\nCall Trace:\n \u003cIRQ\u003e  [\u003cffffffff8025b9b9\u003e] tcp_reset+0x12f/0x1e8\n [\u003cffffffff80046125\u003e] tcp_rcv_state_process+0x1c0/0xa08\n [\u003cffffffff8003eb22\u003e] tcp_v4_do_rcv+0x310/0x37a\n [\u003cffffffff80028bea\u003e] tcp_v4_rcv+0x74d/0xb43\n [\u003cffffffff8024ef4c\u003e] ip_local_deliver_finish+0x0/0x259\n [\u003cffffffff80037131\u003e] ip_local_deliver+0x200/0x2f4\n [\u003cffffffff8003843c\u003e] ip_rcv+0x64c/0x69f\n [\u003cffffffff80021d89\u003e] netif_receive_skb+0x4c4/0x4fa\n [\u003cffffffff80032eca\u003e] process_backlog+0x90/0xec\n [\u003cffffffff8000cc50\u003e] net_rx_action+0xbb/0x1f1\n [\u003cffffffff80012d3a\u003e] __do_softirq+0xf5/0x1ce\n [\u003cffffffff8001147a\u003e] handle_IRQ_event+0x56/0xb0\n [\u003cffffffff8006334c\u003e] call_softirq+0x1c/0x28\n [\u003cffffffff80070476\u003e] do_softirq+0x2c/0x85\n [\u003cffffffff80070441\u003e] do_IRQ+0x149/0x152\n [\u003cffffffff80062665\u003e] ret_from_intr+0x0/0xa\n \u003cEOI\u003e  [\u003cffffffff80008a2e\u003e] __handle_mm_fault+0x6cd/0x1303\n [\u003cffffffff80008903\u003e] __handle_mm_fault+0x5a2/0x1303\n [\u003cffffffff80033a9d\u003e] cache_free_debugcheck+0x21f/0x22e\n [\u003cffffffff8006a263\u003e] do_page_fault+0x49a/0x7dc\n [\u003cffffffff80066487\u003e] thread_return+0x89/0x174\n [\u003cffffffff800c5aee\u003e] audit_syscall_exit+0x341/0x35c\n [\u003cffffffff80062e39\u003e] error_exit+0x0/0x84\n\ntcp_rcv_state_process()\n...  // (sk_state \u003d\u003d TCP_CLOSE_WAIT here)\n...\n        /* step 2: check RST bit */\n        if(th-\u003erst) {\n                tcp_reset(sk);\n                goto discard;\n        }\n...\n---------------------------------\ntcp_rcv_state_process\n tcp_reset\n  tcp_done\n   tcp_set_state(sk, TCP_CLOSE);\n     inet_put_port\n      __inet_put_port\n       inet_sk(sk)-\u003enum \u003d 0;\n\n   sk-\u003esk_shutdown \u003d SHUTDOWN_MASK;\n\n2) After that the process (socket owner) tries to write something to\n   that socket and \"inet_autobind\" sets a _new_ (which differs from\n   the original!) port number for the socket:\n\n Call Trace:\n  [\u003cffffffff80255a12\u003e] inet_bind_hash+0x33/0x5f\n  [\u003cffffffff80257180\u003e] inet_csk_get_port+0x216/0x268\n  [\u003cffffffff8026bcc9\u003e] inet_autobind+0x22/0x8f\n  [\u003cffffffff80049140\u003e] inet_sendmsg+0x27/0x57\n  [\u003cffffffff8003a9d9\u003e] do_sock_write+0xae/0xea\n  [\u003cffffffff80226ac7\u003e] sock_writev+0xdc/0xf6\n  [\u003cffffffff800680c7\u003e] _spin_lock_irqsave+0x9/0xe\n  [\u003cffffffff8001fb49\u003e] __pollwait+0x0/0xdd\n  [\u003cffffffff8008d533\u003e] default_wake_function+0x0/0xe\n  [\u003cffffffff800a4f10\u003e] autoremove_wake_function+0x0/0x2e\n  [\u003cffffffff800f0b49\u003e] do_readv_writev+0x163/0x274\n  [\u003cffffffff80066538\u003e] thread_return+0x13a/0x174\n  [\u003cffffffff800145d8\u003e] tcp_poll+0x0/0x1c9\n  [\u003cffffffff800c56d3\u003e] audit_syscall_entry+0x180/0x1b3\n  [\u003cffffffff800f0dd0\u003e] sys_writev+0x49/0xe4\n  [\u003cffffffff800622dd\u003e] tracesys+0xd5/0xe0\n\n3) sendmsg fails at last with -EPIPE (\u003d\u003e \u0027write\u0027 returns -EPIPE in userspace):\n\nF: tcp_sendmsg1 -EPIPE: sk\u003dffff81000bda00d0, sport\u003d49847, old_state\u003d7, new_state\u003d7, sk_err\u003d0, sk_shutdown\u003d3\n\nCall Trace:\n [\u003cffffffff80027557\u003e] tcp_sendmsg+0xcb/0xe87\n [\u003cffffffff80033300\u003e] release_sock+0x10/0xae\n [\u003cffffffff8016f20f\u003e] vgacon_cursor+0x0/0x1a7\n [\u003cffffffff8026bd32\u003e] inet_autobind+0x8b/0x8f\n [\u003cffffffff8003a9d9\u003e] do_sock_write+0xae/0xea\n [\u003cffffffff80226ac7\u003e] sock_writev+0xdc/0xf6\n [\u003cffffffff800680c7\u003e] _spin_lock_irqsave+0x9/0xe\n [\u003cffffffff8001fb49\u003e] __pollwait+0x0/0xdd\n [\u003cffffffff8008d533\u003e] default_wake_function+0x0/0xe\n [\u003cffffffff800a4f10\u003e] autoremove_wake_function+0x0/0x2e\n [\u003cffffffff800f0b49\u003e] do_readv_writev+0x163/0x274\n [\u003cffffffff80066538\u003e] thread_return+0x13a/0x174\n [\u003cffffffff800145d8\u003e] tcp_poll+0x0/0x1c9\n [\u003cffffffff800c56d3\u003e] audit_syscall_entry+0x180/0x1b3\n [\u003cffffffff800f0dd0\u003e] sys_writev+0x49/0xe4\n [\u003cffffffff800622dd\u003e] tracesys+0xd5/0xe0\n\ntcp_sendmsg()\n...\n        /* Wait for a connection to finish. */\n        if ((1 \u003c\u003c sk-\u003esk_state) \u0026 ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {\n                int old_state \u003d sk-\u003esk_state;\n                if ((err \u003d sk_stream_wait_connect(sk, \u0026timeo)) !\u003d 0) {\nif (f_d \u0026\u0026 (err \u003d\u003d -EPIPE)) {\n        printk(\"F: tcp_sendmsg1 -EPIPE: sk\u003d%p, sport\u003d%u, old_state\u003d%d, new_state\u003d%d, \"\n                \"sk_err\u003d%d, sk_shutdown\u003d%d\\n\",\n                sk, ntohs(inet_sk(sk)-\u003esport), old_state, sk-\u003esk_state,\n                sk-\u003esk_err, sk-\u003esk_shutdown);\n        dump_stack();\n}\n                        goto out_err;\n                }\n        }\n...\n\n4) Then the process (socket owner) understands that it\u0027s time to close\n   that socket and does that (and thus triggers sending reset packet):\n\nCall Trace:\n...\n [\u003cffffffff80032077\u003e] dev_queue_xmit+0x343/0x3d6\n [\u003cffffffff80034698\u003e] ip_output+0x351/0x384\n [\u003cffffffff80251ae9\u003e] dst_output+0x0/0xe\n [\u003cffffffff80036ec6\u003e] ip_queue_xmit+0x567/0x5d2\n [\u003cffffffff80095700\u003e] vprintk+0x21/0x33\n [\u003cffffffff800070f0\u003e] check_poison_obj+0x2e/0x206\n [\u003cffffffff80013587\u003e] poison_obj+0x36/0x45\n [\u003cffffffff8025dea6\u003e] tcp_send_active_reset+0x15/0x14d\n [\u003cffffffff80023481\u003e] dbg_redzone1+0x1c/0x25\n [\u003cffffffff8025dea6\u003e] tcp_send_active_reset+0x15/0x14d\n [\u003cffffffff8000ca94\u003e] cache_alloc_debugcheck_after+0x189/0x1c8\n [\u003cffffffff80023405\u003e] tcp_transmit_skb+0x764/0x786\n [\u003cffffffff8025df8a\u003e] tcp_send_active_reset+0xf9/0x14d\n [\u003cffffffff80258ff1\u003e] tcp_close+0x39a/0x960\n [\u003cffffffff8026be12\u003e] inet_release+0x69/0x80\n [\u003cffffffff80059b31\u003e] sock_release+0x4f/0xcf\n [\u003cffffffff80059d4c\u003e] sock_close+0x2c/0x30\n [\u003cffffffff800133c9\u003e] __fput+0xac/0x197\n [\u003cffffffff800252bc\u003e] filp_close+0x59/0x61\n [\u003cffffffff8001eff6\u003e] sys_close+0x85/0xc7\n [\u003cffffffff800622dd\u003e] tracesys+0xd5/0xe0\n\nSo, in brief:\n\n* a received packet for socket in TCP_CLOSE_WAIT state triggers\n  tcp_reset() which clears inet_sk(sk)-\u003enum and put socket into\n  TCP_CLOSE state\n\n* an attempt to write to that socket forces inet_autobind() to get a\n  new port (but the write itself fails with -EPIPE)\n\n* tcp_close() called for socket in TCP_CLOSE state sends an active\n  reset via socket with newly allocated port\n\nThis adds an additional check in tcp_close() for already closed\nsockets. We do not want to send anything to closed sockets.\n\nSigned-off-by: Konstantin Khorenko \u003ckhorenko@openvz.org\u003e\nSigned-off-by: David S. Miller \u003cdavem@davemloft.net\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "779d40c3b96efbe76eace0b45b66ada4fe9c4b78",
      "old_mode": 33188,
      "old_path": "net/ipv4/tcp.c",
      "new_id": "d5f84bd5a45508df46871ed52be1e36aa26157ad",
      "new_mode": 33188,
      "new_path": "net/ipv4/tcp.c"
    }
  ]
}
