From a68e59dd1d1af54c5f0bf3c2702e05c39c552477 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 1 Jun 2020 22:40:03 -0400 Subject: [PATCH] freebsd_network: Fix destruction of ref-counted ext_bufs. The check as to whether or not the buf should be freed was wrong, leading to incorrect frees. Fixes double-free KDLs under the idualwifi driver that occur on boot extremely frequently. Change-Id: Ia411a6f5c31dd30764705cd87840797f862b4020 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2862 Reviewed-by: waddlesplash --- src/libs/compat/freebsd_network/mbuf.c | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/libs/compat/freebsd_network/mbuf.c b/src/libs/compat/freebsd_network/mbuf.c index d1f9a837b2..d9389341c8 100644 --- a/src/libs/compat/freebsd_network/mbuf.c +++ b/src/libs/compat/freebsd_network/mbuf.c @@ -235,7 +235,6 @@ m_cljget(struct mbuf* memoryBuffer, int how, int size) static void mb_free_ext(struct mbuf *memoryBuffer) { - object_cache *cache = NULL; volatile u_int *refcnt; struct mbuf *mref; int freembuf; @@ -270,22 +269,24 @@ mb_free_ext(struct mbuf *memoryBuffer) freembuf = 1; /* Free attached storage only if this mbuf is the only reference to it. */ - if (!(*refcnt == 1 || atomic_add(refcnt, -1) == 1) - && !(freembuf && memoryBuffer != mref)) - return; + if (*refcnt == 1 || atomic_add((int32*)refcnt, -1) == 1) { + object_cache *cache = NULL; - if (memoryBuffer->m_ext.ext_type == EXT_CLUSTER) - cache = sChunkCache; - else if (memoryBuffer->m_ext.ext_type == EXT_JUMBO9) - cache = sJumbo9ChunkCache; - else if (memoryBuffer->m_ext.ext_type == EXT_JUMBOP) - cache = sJumboPageSizeCache; - else - panic("unknown mbuf ext_type %d", memoryBuffer->m_ext.ext_type); + if (memoryBuffer->m_ext.ext_type == EXT_CLUSTER) + cache = sChunkCache; + else if (memoryBuffer->m_ext.ext_type == EXT_JUMBO9) + cache = sJumbo9ChunkCache; + else if (memoryBuffer->m_ext.ext_type == EXT_JUMBOP) + cache = sJumboPageSizeCache; + else + panic("unknown mbuf ext_type %d", memoryBuffer->m_ext.ext_type); - object_cache_free(cache, memoryBuffer->m_ext.ext_buf, 0); - memoryBuffer->m_ext.ext_buf = NULL; - object_cache_free(sMBufCache, memoryBuffer, 0); + object_cache_free(cache, memoryBuffer->m_ext.ext_buf, 0); + object_cache_free(sMBufCache, mref, 0); + } + + if (freembuf && memoryBuffer != mref) + object_cache_free(sMBufCache, memoryBuffer, 0); }