summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2008-09-25 17:26:54 +0000
committerrwatson <rwatson@FreeBSD.org>2008-09-25 17:26:54 +0000
commitc534a9e1e582bf57dbc941cf1a1540246ef42b56 (patch)
tree1caf2bf05f7647466396bf179ae63be90d554fd4
parenta00bc49d3692d7dba5546cf2cb1e1375886148c5 (diff)
downloadFreeBSD-src-c534a9e1e582bf57dbc941cf1a1540246ef42b56.zip
FreeBSD-src-c534a9e1e582bf57dbc941cf1a1540246ef42b56.tar.gz
As a follow-on to r183323, correct another case where ip_output() was
called without an inpcb pointer despite holding the tcbinfo global lock, which lead to a deadlock or panic when ipfw tried to further acquire it recursively. Reported by: Stefan Ehmann <shoesoft at gmx dot net> MFC after: 3 days
-rw-r--r--sys/netinet/tcp_input.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index ab18c60..78ea22f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -885,13 +885,29 @@ findpcb:
dropwithreset:
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
- tcp_dropwithreset(m, th, tp, tlen, rstreason);
+
+ /*
+ * If inp is non-NULL, we call tcp_dropwithreset() holding both inpcb
+ * and global locks. However, if NULL, we must hold neither as
+ * firewalls may acquire the global lock in order to look for a
+ * matching inpcb.
+ */
+ if (inp != NULL) {
+ tcp_dropwithreset(m, th, tp, tlen, rstreason);
+ INP_WUNLOCK(inp);
+ }
+ INP_INFO_WUNLOCK(&V_tcbinfo);
+ if (inp == NULL)
+ tcp_dropwithreset(m, th, NULL, tlen, rstreason);
m = NULL; /* mbuf chain got consumed. */
+ goto drop;
+
dropunlock:
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
if (inp != NULL)
INP_WUNLOCK(inp);
INP_INFO_WUNLOCK(&V_tcbinfo);
+
drop:
INP_INFO_UNLOCK_ASSERT(&V_tcbinfo);
if (s != NULL)
OpenPOWER on IntegriCloud