Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

inet: reqsk_alloc() needs to take care of dead listeners

We'll soon no longer take a refcount on listeners,
so reqsk_alloc() can not assume a listener refcount is not
zero. We need to use atomic_inc_not_zero()

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
3a5d1c0e 2d331915

+15 -16
+15 -16
include/net/request_sock.h
··· 85 85 struct request_sock *req; 86 86 87 87 req = kmem_cache_alloc(ops->slab, GFP_ATOMIC | __GFP_NOWARN); 88 - 89 - if (req) { 90 - req->rsk_ops = ops; 91 - if (attach_listener) { 92 - sock_hold(sk_listener); 93 - req->rsk_listener = sk_listener; 94 - } else { 95 - req->rsk_listener = NULL; 88 + if (!req) 89 + return NULL; 90 + req->rsk_listener = NULL; 91 + if (attach_listener) { 92 + if (unlikely(!atomic_inc_not_zero(&sk_listener->sk_refcnt))) { 93 + kmem_cache_free(ops->slab, req); 94 + return NULL; 96 95 } 97 - req_to_sk(req)->sk_prot = sk_listener->sk_prot; 98 - sk_node_init(&req_to_sk(req)->sk_node); 99 - sk_tx_queue_clear(req_to_sk(req)); 100 - req->saved_syn = NULL; 101 - /* Following is temporary. It is coupled with debugging 102 - * helpers in reqsk_put() & reqsk_free() 103 - */ 104 - atomic_set(&req->rsk_refcnt, 0); 96 + req->rsk_listener = sk_listener; 105 97 } 98 + req->rsk_ops = ops; 99 + req_to_sk(req)->sk_prot = sk_listener->sk_prot; 100 + sk_node_init(&req_to_sk(req)->sk_node); 101 + sk_tx_queue_clear(req_to_sk(req)); 102 + req->saved_syn = NULL; 103 + atomic_set(&req->rsk_refcnt, 0); 104 + 106 105 return req; 107 106 } 108 107