summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-17 14:07:47 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2008-08-01 11:51:02 -0700
commit09bd119f360128b1944837c2249237686a4ddefc (patch)
tree48d372206286aa04e2504110d6c879d1a0dd8bab
parent482780d80ba2ab6e6bcbb4ec2bf868d2f9bd4628 (diff)
downloadlwn-09bd119f360128b1944837c2249237686a4ddefc.tar.gz
lwn-09bd119f360128b1944837c2249237686a4ddefc.zip
netfilter -stable: nf_conntrack_tcp: fix endless loop
netfilter: nf_conntrack_tcp: fix endless loop Upstream commit 6b69fe0: When a conntrack entry is destroyed in process context and destruction is interrupted by packet processing and the packet is an attempt to reopen a closed connection, TCP conntrack tries to kill the old entry itself and returns NF_REPEAT to pass the packet through the hook again. This may lead to an endless loop: TCP conntrack repeatedly finds the old entry, but can not kill it itself since destruction is already in progress, but destruction in process context can not complete since TCP conntrack is keeping the CPU busy. Drop the packet in TCP conntrack if we can't kill the connection ourselves to avoid this. Reported by: hemao77@gmail.com [ Kernel bugzilla #11058 ] Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index fc43e223ab39..3ddf1c001dae 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -845,9 +845,15 @@ static int tcp_packet(struct nf_conn *ct,
/* Attempt to reopen a closed/aborted connection.
* Delete this connection and look up again. */
write_unlock_bh(&tcp_lock);
- if (del_timer(&ct->timeout))
+ /* Only repeat if we can actually remove the timer.
+ * Destruction may already be in progress in process
+ * context and we must give it a chance to terminate.
+ */
+ if (del_timer(&ct->timeout)) {
ct->timeout.function((unsigned long)ct);
- return -NF_REPEAT;
+ return -NF_REPEAT;
+ }
+ return -NF_DROP;
}
/* Fall through */
case TCP_CONNTRACK_IGNORE: