• C
    inet: Fix kmemleak in tcp_v4/6_syn_recv_sock and dccp_v4/6_request_recv_sock · e337e24d
    Christoph Paasch 提交于
    If in either of the above functions inet_csk_route_child_sock() or
    __inet_inherit_port() fails, the newsk will not be freed:
    
    unreferenced object 0xffff88022e8a92c0 (size 1592):
      comm "softirq", pid 0, jiffies 4294946244 (age 726.160s)
      hex dump (first 32 bytes):
        0a 01 01 01 0a 01 01 02 00 00 00 00 a7 cc 16 00  ................
        02 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00  ................
      backtrace:
        [<ffffffff8153d190>] kmemleak_alloc+0x21/0x3e
        [<ffffffff810ab3e7>] kmem_cache_alloc+0xb5/0xc5
        [<ffffffff8149b65b>] sk_prot_alloc.isra.53+0x2b/0xcd
        [<ffffffff8149b784>] sk_clone_lock+0x16/0x21e
        [<ffffffff814d711a>] inet_csk_clone_lock+0x10/0x7b
        [<ffffffff814ebbc3>] tcp_create_openreq_child+0x21/0x481
        [<ffffffff814e8fa5>] tcp_v4_syn_recv_sock+0x3a/0x23b
        [<ffffffff814ec5ba>] tcp_check_req+0x29f/0x416
        [<ffffffff814e8e10>] tcp_v4_do_rcv+0x161/0x2bc
        [<ffffffff814eb917>] tcp_v4_rcv+0x6c9/0x701
        [<ffffffff814cea9f>] ip_local_deliver_finish+0x70/0xc4
        [<ffffffff814cec20>] ip_local_deliver+0x4e/0x7f
        [<ffffffff814ce9f8>] ip_rcv_finish+0x1fc/0x233
        [<ffffffff814cee68>] ip_rcv+0x217/0x267
        [<ffffffff814a7bbe>] __netif_receive_skb+0x49e/0x553
        [<ffffffff814a7cc3>] netif_receive_skb+0x50/0x82
    
    This happens, because sk_clone_lock initializes sk_refcnt to 2, and thus
    a single sock_put() is not enough to free the memory. Additionally, things
    like xfrm, memcg, cookie_values,... may have been initialized.
    We have to free them properly.
    
    This is fixed by forcing a call to tcp_done(), ending up in
    inet_csk_destroy_sock, doing the final sock_put(). tcp_done() is necessary,
    because it ends up doing all the cleanup on xfrm, memcg, cookie_values,
    xfrm,...
    
    Before calling tcp_done, we have to set the socket to SOCK_DEAD, to
    force it entering inet_csk_destroy_sock. To avoid the warning in
    inet_csk_destroy_sock, inet_num has to be set to 0.
    As inet_csk_destroy_sock does a dec on orphan_count, we first have to
    increase it.
    
    Calling tcp_done() allows us to remove the calls to
    tcp_clear_xmit_timer() and tcp_cleanup_congestion_control().
    
    A similar approach is taken for dccp by calling dccp_done().
    
    This is in the kernel since 093d2823 (tproxy: fix hash locking issue
    when using port redirection in __inet_inherit_port()), thus since
    version >= 2.6.37.
    Signed-off-by: NChristoph Paasch <christoph.paasch@uclouvain.be>
    Signed-off-by: NDavid S. Miller <davem@davemloft.net>
    e337e24d
ipv4.c 28.5 KB