inet: fix race in reqsk_queue_unlink()
reqsk_timer_handler() tests if icsk_accept_queue.listen_opt is NULL at its beginning. By the time it calls inet_csk_reqsk_queue_drop() and reqsk_queue_unlink(), listener might have been closed and inet_csk_listen_stop() had called reqsk_queue_yank_acceptq() which sets icsk_accept_queue.listen_opt to NULL We therefore need to correctly check listen_opt being NULL after holding syn_wait_lock for proper synchronization. Fixes:fa76ce7328
("inet: get rid of central tcp/dccp listener timer") Fixes:b357a364c5
("inet: fix possible panic in reqsk_queue_unlink()") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Yuchung Cheng <ycheng@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8695a144da
commit
2306c704ce
|
@ -577,21 +577,22 @@ EXPORT_SYMBOL(inet_rtx_syn_ack);
|
|||
static bool reqsk_queue_unlink(struct request_sock_queue *queue,
|
||||
struct request_sock *req)
|
||||
{
|
||||
struct listen_sock *lopt = queue->listen_opt;
|
||||
struct request_sock **prev;
|
||||
struct listen_sock *lopt;
|
||||
bool found = false;
|
||||
|
||||
spin_lock(&queue->syn_wait_lock);
|
||||
|
||||
for (prev = &lopt->syn_table[req->rsk_hash]; *prev != NULL;
|
||||
prev = &(*prev)->dl_next) {
|
||||
if (*prev == req) {
|
||||
*prev = req->dl_next;
|
||||
found = true;
|
||||
break;
|
||||
lopt = queue->listen_opt;
|
||||
if (lopt) {
|
||||
for (prev = &lopt->syn_table[req->rsk_hash]; *prev != NULL;
|
||||
prev = &(*prev)->dl_next) {
|
||||
if (*prev == req) {
|
||||
*prev = req->dl_next;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&queue->syn_wait_lock);
|
||||
if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer))
|
||||
reqsk_put(req);
|
||||
|
|
Loading…
Reference in a new issue