diff --git a/packages/linux/patches/4.1.10/linux-999.10-inet-fix-race-in-reqsk_queue_unlink.patch b/packages/linux/patches/4.1.10/linux-999.10-inet-fix-race-in-reqsk_queue_unlink.patch new file mode 100644 index 0000000000..c5c766990d --- /dev/null +++ b/packages/linux/patches/4.1.10/linux-999.10-inet-fix-race-in-reqsk_queue_unlink.patch @@ -0,0 +1,63 @@ +From 8f6a05588928ef61e751ca3cb008b9847fb6b83d Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Thu, 1 Oct 2015 05:39:26 -0700 +Subject: [PATCH] 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: fa76ce7328b2 ("inet: get rid of central tcp/dccp listener timer") +Fixes: b357a364c57c ("inet: fix possible panic in reqsk_queue_unlink()") +Signed-off-by: Eric Dumazet +Cc: Yuchung Cheng +--- + net/ipv4/inet_connection_sock.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index e664706b350c..37c8b45af44b 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -568,21 +568,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); +-- +2.4.3 + diff --git a/packages/linux/patches/4.1.10/linux-999.11-inet-fix-potential-deadlock-in-reqsk_queue_unlink.patch b/packages/linux/patches/4.1.10/linux-999.11-inet-fix-potential-deadlock-in-reqsk_queue_unlink.patch new file mode 100644 index 0000000000..b6c9f34dc9 --- /dev/null +++ b/packages/linux/patches/4.1.10/linux-999.11-inet-fix-potential-deadlock-in-reqsk_queue_unlink.patch @@ -0,0 +1,40 @@ +From 05676fe53c9f26fe703c57b14bdd0807e23cc33b Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Thu, 13 Aug 2015 15:44:51 -0700 +Subject: [PATCH 1/2] inet: fix potential deadlock in reqsk_queue_unlink() + +When replacing del_timer() with del_timer_sync(), I introduced +a deadlock condition : + +reqsk_queue_unlink() is called from inet_csk_reqsk_queue_drop() + +inet_csk_reqsk_queue_drop() can be called from many contexts, +one being the timer handler itself (reqsk_timer_handler()). + +In this case, del_timer_sync() loops forever. + +Simple fix is to test if timer is pending. + +Fixes: 2235f2ac75fd ("inet: fix races with reqsk timers") +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + net/ipv4/inet_connection_sock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index b27fc401c6a9..e664706b350c 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -584,7 +584,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue, + } + + spin_unlock(&queue->syn_wait_lock); +- if (del_timer_sync(&req->rsk_timer)) ++ if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer)) + reqsk_put(req); + return found; + } +-- +2.4.3 +