The branch main has been updated by mav:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a03c23931eec567b0957c2a0b1102dba8d538d98

commit a03c23931eec567b0957c2a0b1102dba8d538d98
Author:     Alexander Motin <m...@freebsd.org>
AuthorDate: 2023-11-10 00:46:26 +0000
Commit:     Alexander Motin <m...@freebsd.org>
CommitDate: 2023-11-10 00:46:26 +0000

    uma: Improve memory modified after free panic messages
    
     - Pass zone pointer to trash_ctor() and report zone name in the panic
    message.  It may be difficult to figyre out zone just by the item size.
     - Do not pass user arguments to internal trash calls, pass thezone.
     - Report malloc type name in the same unified panic message.
     - Report corruption offset from the beginning of the items instead of
    the full pointer.  It makes panic message shorter and more readable.
---
 sys/kern/kern_malloc.c |  4 +--
 sys/kern/kern_mbuf.c   |  6 ++---
 sys/vm/uma_core.c      |  4 +--
 sys/vm/uma_dbg.c       | 67 ++++++++++++++++++++++++++++++++++----------------
 4 files changed, 53 insertions(+), 28 deletions(-)

diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index 07f59f733e6a..da7408edd186 100644
--- a/sys/kern/kern_malloc.c
+++ b/sys/kern/kern_malloc.c
@@ -650,7 +650,7 @@ void *
                size = (size & ~KMEM_ZMASK) + KMEM_ZBASE;
        indx = kmemsize[size >> KMEM_ZSHIFT];
        zone = kmemzones[indx].kz_zone[mtp_get_subzone(mtp)];
-       va = uma_zalloc(zone, flags);
+       va = uma_zalloc_arg(zone, zone, flags);
        if (va != NULL) {
                size = zone->uz_size;
                if ((flags & M_ZERO) == 0) {
@@ -690,7 +690,7 @@ malloc_domain(size_t *sizep, int *indxp, struct malloc_type 
*mtp, int domain,
                size = (size & ~KMEM_ZMASK) + KMEM_ZBASE;
        indx = kmemsize[size >> KMEM_ZSHIFT];
        zone = kmemzones[indx].kz_zone[mtp_get_subzone(mtp)];
-       va = uma_zalloc_domain(zone, NULL, domain, flags);
+       va = uma_zalloc_domain(zone, zone, domain, flags);
        if (va != NULL)
                *sizep = zone->uz_size;
        *indxp = indx;
diff --git a/sys/kern/kern_mbuf.c b/sys/kern/kern_mbuf.c
index 0897ac4cc2db..60c638735ec4 100644
--- a/sys/kern/kern_mbuf.c
+++ b/sys/kern/kern_mbuf.c
@@ -703,7 +703,7 @@ mb_dtor_pack(void *mem, int size, void *arg)
        KASSERT(m->m_ext.ext_size == MCLBYTES, ("%s: ext_size != MCLBYTES", 
__func__));
        KASSERT(m->m_ext.ext_type == EXT_PACKET, ("%s: ext_type != EXT_PACKET", 
__func__));
 #if defined(INVARIANTS) && !defined(KMSAN)
-       trash_dtor(m->m_ext.ext_buf, MCLBYTES, arg);
+       trash_dtor(m->m_ext.ext_buf, MCLBYTES, zone_clust);
 #endif
        /*
         * If there are processes blocked on zone_clust, waiting for pages
@@ -782,7 +782,7 @@ mb_zfini_pack(void *mem, int size)
 #endif
        uma_zfree_arg(zone_clust, m->m_ext.ext_buf, NULL);
 #if defined(INVARIANTS) && !defined(KMSAN)
-       trash_dtor(mem, size, NULL);
+       trash_dtor(mem, size, zone_clust);
 #endif
 }
 
@@ -804,7 +804,7 @@ mb_ctor_pack(void *mem, int size, void *arg, int how)
        MPASS((flags & M_NOFREE) == 0);
 
 #if defined(INVARIANTS) && !defined(KMSAN)
-       trash_ctor(m->m_ext.ext_buf, MCLBYTES, arg, how);
+       trash_ctor(m->m_ext.ext_buf, MCLBYTES, zone_clust, how);
 #endif
 
        error = m_init(m, how, type, flags);
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c
index 661c98b272da..d185f12448ee 100644
--- a/sys/vm/uma_core.c
+++ b/sys/vm/uma_core.c
@@ -3468,7 +3468,7 @@ item_ctor(uma_zone_t zone, int uz_flags, int size, void 
*udata, int flags,
        skipdbg = uma_dbg_zskip(zone, item);
        if (!skipdbg && (uz_flags & UMA_ZFLAG_TRASH) != 0 &&
            zone->uz_ctor != trash_ctor)
-               trash_ctor(item, size, udata, flags);
+               trash_ctor(item, size, zone, flags);
 #endif
 
        /* Check flags before loading ctor pointer. */
@@ -3510,7 +3510,7 @@ item_dtor(uma_zone_t zone, void *item, int size, void 
*udata,
 #ifdef INVARIANTS
                if (!skipdbg && (zone->uz_flags & UMA_ZFLAG_TRASH) != 0 &&
                    zone->uz_dtor != trash_dtor)
-                       trash_dtor(item, size, udata);
+                       trash_dtor(item, size, zone);
 #endif
        }
        kasan_mark_item_invalid(zone, item);
diff --git a/sys/vm/uma_dbg.c b/sys/vm/uma_dbg.c
index 76dd2bfde2fe..c256e62875c0 100644
--- a/sys/vm/uma_dbg.c
+++ b/sys/vm/uma_dbg.c
@@ -53,18 +53,22 @@
 #include <vm/uma_dbg.h>
 #include <vm/memguard.h>
 
+#include <machine/stack.h>
+
 static const u_long uma_junk = (u_long)0xdeadc0dedeadc0de;
 
 /*
  * Checks an item to make sure it hasn't been overwritten since it was freed,
  * prior to subsequent reallocation.
  *
- * Complies with standard ctor arg/return
+ * Complies with standard ctor arg/return.  arg should be zone pointer or NULL.
  */
 int
 trash_ctor(void *mem, int size, void *arg, int flags)
 {
+       struct uma_zone *zone = arg;
        u_long *p = mem, *e;
+       int off;
 
 #ifdef DEBUG_MEMGUARD
        if (is_memguard_addr(mem))
@@ -73,19 +77,22 @@ trash_ctor(void *mem, int size, void *arg, int flags)
 
        e = p + size / sizeof(*p);
        for (; p < e; p++) {
-               if (__predict_true(*p == uma_junk))
-                       continue;
-               panic("Memory modified after free %p(%d) val=%lx @ %p\n",
-                   mem, size, *p, p);
+               if (__predict_false(*p != uma_junk))
+                       goto dopanic;
        }
        return (0);
+
+dopanic:
+       off = (uintptr_t)p - (uintptr_t)mem;
+       panic("Memory modified after free %p (%d, %s) + %d = %lx\n",
+           mem, size, zone ? zone->uz_name : "", off,  *p);
+       return (0);
 }
 
 /*
  * Fills an item with predictable garbage
  *
  * Complies with standard dtor arg/return
- *
  */
 void
 trash_dtor(void *mem, int size, void *arg)
@@ -106,7 +113,6 @@ trash_dtor(void *mem, int size, void *arg)
  * Fills an item with predictable garbage
  *
  * Complies with standard init arg/return
- *
  */
 int
 trash_init(void *mem, int size, int flags)
@@ -116,10 +122,10 @@ trash_init(void *mem, int size, int flags)
 }
 
 /*
- * Checks an item to make sure it hasn't been overwritten since it was freed.
+ * Checks an item to make sure it hasn't been overwritten since it was freed,
+ * prior to freeing it back to available memory.
  *
  * Complies with standard fini arg/return
- *
  */
 void
 trash_fini(void *mem, int size)
@@ -127,11 +133,19 @@ trash_fini(void *mem, int size)
        (void)trash_ctor(mem, size, NULL, 0);
 }
 
+/*
+ * Checks an item to make sure it hasn't been overwritten since it was freed,
+ * prior to subsequent reallocation.
+ *
+ * Complies with standard ctor arg/return.  arg should be zone pointer or NULL.
+ */
 int
 mtrash_ctor(void *mem, int size, void *arg, int flags)
 {
-       struct malloc_type **ksp;
+       struct uma_zone *zone = arg;
        u_long *p = mem, *e;
+       struct malloc_type **ksp;
+       int off, osize = size;
 
 #ifdef DEBUG_MEMGUARD
        if (is_memguard_addr(mem))
@@ -139,17 +153,31 @@ mtrash_ctor(void *mem, int size, void *arg, int flags)
 #endif
 
        size -= sizeof(struct malloc_type *);
-       ksp = (struct malloc_type **)mem;
-       ksp += size / sizeof(struct malloc_type *);
 
        e = p + size / sizeof(*p);
        for (; p < e; p++) {
-               if (__predict_true(*p == uma_junk))
-                       continue;
-               printf("Memory modified after free %p(%d) val=%lx @ %p\n",
-                   mem, size, *p, p);
-               panic("Most recently used by %s\n", (*ksp == NULL)?
-                   "none" : (*ksp)->ks_shortdesc);
+               if (__predict_false(*p != uma_junk))
+                       goto dopanic;
+       }
+       return (0);
+
+dopanic:
+       off = (uintptr_t)p - (uintptr_t)mem;
+       ksp = (struct malloc_type **)mem;
+       ksp += size / sizeof(struct malloc_type *);
+       if (*ksp != NULL && INKERNEL((uintptr_t)*ksp)) {
+               /*
+                * If *ksp is corrupted we may be unable to panic clean,
+                * so print what we have reliably while we still can.
+                */
+               printf("Memory modified after free %p (%d, %s, %p) + %d = 
%lx\n",
+                   mem, osize, zone ? zone->uz_name : "", *ksp, off, *p);
+               panic("Memory modified after free %p (%d, %s, %s) + %d = %lx\n",
+                   mem, osize, zone ? zone->uz_name : "", (*ksp)->ks_shortdesc,
+                   off, *p);
+       } else {
+               panic("Memory modified after free %p (%d, %s, %p) + %d = %lx\n",
+                   mem, osize, zone ? zone->uz_name : "", *ksp, off, *p);
        }
        return (0);
 }
@@ -158,7 +186,6 @@ mtrash_ctor(void *mem, int size, void *arg, int flags)
  * Fills an item with predictable garbage
  *
  * Complies with standard dtor arg/return
- *
  */
 void
 mtrash_dtor(void *mem, int size, void *arg)
@@ -181,7 +208,6 @@ mtrash_dtor(void *mem, int size, void *arg)
  * Fills an item with predictable garbage
  *
  * Complies with standard init arg/return
- *
  */
 int
 mtrash_init(void *mem, int size, int flags)
@@ -206,7 +232,6 @@ mtrash_init(void *mem, int size, int flags)
  * prior to freeing it back to available memory.
  *
  * Complies with standard fini arg/return
- *
  */
 void
 mtrash_fini(void *mem, int size)

Reply via email to