Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2306c704 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: fa76ce73 ("inet: get rid of central tcp/dccp listener timer")
Fixes: b357a364 ("inet: fix possible panic in reqsk_queue_unlink()")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8695a144
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -577,12 +577,13 @@ 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);

	lopt = queue->listen_opt;
	if (lopt) {
		for (prev = &lopt->syn_table[req->rsk_hash]; *prev != NULL;
		     prev = &(*prev)->dl_next) {
			if (*prev == req) {
@@ -591,7 +592,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue,
				break;
			}
		}

	}
	spin_unlock(&queue->syn_wait_lock);
	if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer))
		reqsk_put(req);