summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorfabient <fabient@FreeBSD.org>2015-12-02 17:26:37 +0000
committerfabient <fabient@FreeBSD.org>2015-12-02 17:26:37 +0000
commitccce6feaa419fbc5fc1c0f617f6ad974b07a58c4 (patch)
treea1cd026229b0606e80d7222dcdfa2c995e639a3f /sys/netinet
parent904bdb8bc249483f4b14b6df43fb361e87b438da (diff)
downloadFreeBSD-src-ccce6feaa419fbc5fc1c0f617f6ad974b07a58c4.zip
FreeBSD-src-ccce6feaa419fbc5fc1c0f617f6ad974b07a58c4.tar.gz
MFC r291301:
The r241129 description was wrong that the scenario is possible only for read locks on pcbs. The same race can happen with write lock semantics as well. The race scenario: - Two threads (1 and 2) locate pcb with writer semantics (INPLOOKUP_WLOCKPCB) and do in_pcbref() on it. - 1 and 2 both drop the inp hash lock. - Another thread (3) grabs the inp hash lock. Then it runs in_pcbfree(), which wlocks the pcb. They must happen faster than 1 or 2 come INP_WLOCK()! - 1 and 2 congest in INP_WLOCK(). - 3 does in_pcbremlists(), drops hash lock, and runs in_pcbrele_wlocked(), which doesn't free the pcb due to two references on it. Then it unlocks the pcb. - 1 (or 2) gets wlock on the pcb, runs in_pcbrele_wlocked(), which doesn't report inp as freed, due to 2 (or 1) still helding extra reference on it. The thread tries to do smth with a disconnected pcb and crashes. Submitted by: emeric.poupon@stormshield.eu Reviewed by: glebius@ Sponsored by: Stormshield Tested by: Cassiano Peixoto, Stormshield
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in_pcb.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 4e75f13..0b296e0 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1148,8 +1148,17 @@ in_pcbrele_wlocked(struct inpcb *inp)
INP_WLOCK_ASSERT(inp);
- if (refcount_release(&inp->inp_refcount) == 0)
+ if (refcount_release(&inp->inp_refcount) == 0) {
+ /*
+ * If the inpcb has been freed, let the caller know, even if
+ * this isn't the last reference.
+ */
+ if (inp->inp_flags2 & INP_FREED) {
+ INP_WUNLOCK(inp);
+ return (1);
+ }
return (0);
+ }
KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__));
OpenPOWER on IntegriCloud