diff options
author | rwatson <rwatson@FreeBSD.org> | 2008-09-25 17:26:54 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2008-09-25 17:26:54 +0000 |
commit | c534a9e1e582bf57dbc941cf1a1540246ef42b56 (patch) | |
tree | 1caf2bf05f7647466396bf179ae63be90d554fd4 | |
parent | a00bc49d3692d7dba5546cf2cb1e1375886148c5 (diff) | |
download | FreeBSD-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.c | 18 |
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) |