The branch main has been updated by markj:

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

commit 100949103a6340aff8a6a4caf1927374c242721c
Author:     Mark Johnston <[email protected]>
AuthorDate: 2021-08-10 21:15:03 +0000
Commit:     Mark Johnston <[email protected]>
CommitDate: 2021-08-11 01:27:54 +0000

    uma: Add KMSAN hooks
    
    For now, just hook the allocation path: upon allocation, items are
    marked as initialized (absent M_ZERO).  Some zones are exempted from
    this when it would otherwise raise false positives.
    
    Use kmsan_orig() to update the origin map for UMA and malloc(9)
    allocations.  This allows KMSAN to print the return address when an
    uninitialized UMA item is implicated in a report.  For example:
      panic: MSan: Uninitialized UMA memory from m_getm2+0x7fe
    
    Sponsored by:   The FreeBSD Foundation
---
 sys/kern/kern_malloc.c | 16 +++++++++++--
 sys/kern/kern_mbuf.c   | 10 ++++----
 sys/vm/uma_core.c      | 62 +++++++++++++++++++++++++++++++++++++++++++++++---
 sys/vm/vm_glue.c       |  2 ++
 4 files changed, 80 insertions(+), 10 deletions(-)

diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index b30139830a1b..0bdce47b37b4 100644
--- a/sys/kern/kern_malloc.c
+++ b/sys/kern/kern_malloc.c
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
+#include <sys/msan.h>
 #include <sys/mutex.h>
 #include <sys/vmmeter.h>
 #include <sys/proc.h>
@@ -654,8 +655,13 @@ void *
        indx = kmemsize[size >> KMEM_ZSHIFT];
        zone = kmemzones[indx].kz_zone[mtp_get_subzone(mtp)];
        va = uma_zalloc(zone, flags);
-       if (va != NULL)
+       if (va != NULL) {
                size = zone->uz_size;
+               if ((flags & M_ZERO) == 0) {
+                       kmsan_mark(va, size, KMSAN_STATE_UNINIT);
+                       kmsan_orig(va, size, KMSAN_TYPE_MALLOC, KMSAN_RET_ADDR);
+               }
+       }
        malloc_type_zone_allocated(mtp, va == NULL ? 0 : size, indx);
        if (__predict_false(va == NULL)) {
                KASSERT((flags & M_WAITOK) == 0,
@@ -735,6 +741,12 @@ malloc_domainset(size_t size, struct malloc_type *mtp, 
struct domainset *ds,
 #ifdef KASAN
        if (va != NULL)
                kasan_mark((void *)va, osize, size, KASAN_MALLOC_REDZONE);
+#endif
+#ifdef KMSAN
+       if ((flags & M_ZERO) == 0) {
+               kmsan_mark(va, size, KMSAN_STATE_UNINIT);
+               kmsan_orig(va, size, KMSAN_TYPE_MALLOC, KMSAN_RET_ADDR);
+       }
 #endif
        return (va);
 }
@@ -1232,7 +1244,7 @@ mallocinit(void *dummy)
                for (subzone = 0; subzone < numzones; subzone++) {
                        kmemzones[indx].kz_zone[subzone] =
                            uma_zcreate(name, size,
-#if defined(INVARIANTS) && !defined(KASAN)
+#if defined(INVARIANTS) && !defined(KASAN) && !defined(KMSAN)
                            mtrash_ctor, mtrash_dtor, mtrash_init, mtrash_fini,
 #else
                            NULL, NULL, NULL, NULL,
diff --git a/sys/kern/kern_mbuf.c b/sys/kern/kern_mbuf.c
index c43f086bb83f..ae4aa7d7e96a 100644
--- a/sys/kern/kern_mbuf.c
+++ b/sys/kern/kern_mbuf.c
@@ -683,7 +683,7 @@ mb_dtor_pack(void *mem, int size, void *arg)
        KASSERT(m->m_ext.ext_arg2 == NULL, ("%s: ext_arg2 != NULL", __func__));
        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__));
-#ifdef INVARIANTS
+#if defined(INVARIANTS) && !defined(KMSAN)
        trash_dtor(m->m_ext.ext_buf, MCLBYTES, arg);
 #endif
        /*
@@ -742,7 +742,7 @@ mb_zinit_pack(void *mem, int size, int how)
            m->m_ext.ext_buf == NULL)
                return (ENOMEM);
        m->m_ext.ext_type = EXT_PACKET; /* Override. */
-#ifdef INVARIANTS
+#if defined(INVARIANTS) && !defined(KMSAN)
        trash_init(m->m_ext.ext_buf, MCLBYTES, how);
 #endif
        return (0);
@@ -758,11 +758,11 @@ mb_zfini_pack(void *mem, int size)
        struct mbuf *m;
 
        m = (struct mbuf *)mem;
-#ifdef INVARIANTS
+#if defined(INVARIANTS) && !defined(KMSAN)
        trash_fini(m->m_ext.ext_buf, MCLBYTES);
 #endif
        uma_zfree_arg(zone_clust, m->m_ext.ext_buf, NULL);
-#ifdef INVARIANTS
+#if defined(INVARIANTS) && !defined(KMSAN)
        trash_dtor(mem, size, NULL);
 #endif
 }
@@ -784,7 +784,7 @@ mb_ctor_pack(void *mem, int size, void *arg, int how)
        type = args->type;
        MPASS((flags & M_NOFREE) == 0);
 
-#ifdef INVARIANTS
+#if defined(INVARIANTS) && !defined(KMSAN)
        trash_ctor(m->m_ext.ext_buf, MCLBYTES, arg, how);
 #endif
 
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c
index 59cc960d3dd9..cdf3d482679e 100644
--- a/sys/vm/uma_core.c
+++ b/sys/vm/uma_core.c
@@ -69,7 +69,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/ktr.h>
 #include <sys/lock.h>
-#include <sys/sysctl.h>
+#include <sys/msan.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/random.h>
@@ -79,6 +79,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sleepqueue.h>
 #include <sys/smp.h>
 #include <sys/smr.h>
+#include <sys/sysctl.h>
 #include <sys/taskqueue.h>
 #include <sys/vmmeter.h>
 
@@ -632,6 +633,60 @@ kasan_mark_slab_invalid(uma_keg_t keg __unused, void *mem 
__unused)
 }
 #endif /* KASAN */
 
+#ifdef KMSAN
+static inline void
+kmsan_mark_item_uninitialized(uma_zone_t zone, void *item)
+{
+       void *pcpu_item;
+       size_t sz;
+       int i;
+
+       if ((zone->uz_flags &
+           (UMA_ZFLAG_CACHE | UMA_ZONE_SECONDARY | UMA_ZONE_MALLOC)) != 0) {
+               /*
+                * Cache zones should not be instrumented by default, as UMA
+                * does not have enough information to do so correctly.
+                * Consumers can mark items themselves if it makes sense to do
+                * so.
+                *
+                * Items from secondary zones are initialized by the parent
+                * zone and thus cannot safely be marked by UMA.
+                *
+                * malloc zones are handled directly by malloc(9) and friends,
+                * since they can provide more precise origin tracking.
+                */
+               return;
+       }
+       if (zone->uz_keg->uk_init != NULL) {
+               /*
+                * By definition, initialized items cannot be marked.  The
+                * best we can do is mark items from these zones after they
+                * are freed to the keg.
+                */
+               return;
+       }
+
+       sz = zone->uz_size;
+       if ((zone->uz_flags & UMA_ZONE_PCPU) == 0) {
+               kmsan_orig(item, sz, KMSAN_TYPE_UMA, KMSAN_RET_ADDR);
+               kmsan_mark(item, sz, KMSAN_STATE_UNINIT);
+       } else {
+               pcpu_item = zpcpu_base_to_offset(item);
+               for (i = 0; i <= mp_maxid; i++) {
+                       kmsan_orig(zpcpu_get_cpu(pcpu_item, i), sz,
+                           KMSAN_TYPE_UMA, KMSAN_RET_ADDR);
+                       kmsan_mark(zpcpu_get_cpu(pcpu_item, i), sz,
+                           KMSAN_STATE_INITED);
+               }
+       }
+}
+#else /* !KMSAN */
+static inline void
+kmsan_mark_item_uninitialized(uma_zone_t zone __unused, void *item __unused)
+{
+}
+#endif /* KMSAN */
+
 /*
  * Acquire the domain lock and record contention.
  */
@@ -2799,7 +2854,7 @@ zone_ctor(void *mem, int size, void *udata, int flags)
                STAILQ_INIT(&zdom->uzd_buckets);
        }
 
-#if defined(INVARIANTS) && !defined(KASAN)
+#if defined(INVARIANTS) && !defined(KASAN) && !defined(KMSAN)
        if (arg->uminit == trash_init && arg->fini == trash_fini)
                zone->uz_flags |= UMA_ZFLAG_TRASH | UMA_ZFLAG_CTORDTOR;
 #elif defined(KASAN)
@@ -3227,7 +3282,7 @@ uma_zcreate(const char *name, size_t size, uma_ctor ctor, 
uma_dtor dtor,
        args.dtor = dtor;
        args.uminit = uminit;
        args.fini = fini;
-#if defined(INVARIANTS) && !defined(KASAN)
+#if defined(INVARIANTS) && !defined(KASAN) && !defined(KMSAN)
        /*
         * Inject procedures which check for memory use after free if we are
         * allowed to scramble the memory while it is not allocated.  This
@@ -3387,6 +3442,7 @@ item_ctor(uma_zone_t zone, int uz_flags, int size, void 
*udata, int flags,
 #endif
 
        kasan_mark_item_valid(zone, item);
+       kmsan_mark_item_uninitialized(zone, item);
 
 #ifdef INVARIANTS
        skipdbg = uma_dbg_zskip(zone, item);
diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c
index 7cfb08246f9e..5e118a7ad86e 100644
--- a/sys/vm/vm_glue.c
+++ b/sys/vm/vm_glue.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
+#include <sys/msan.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/racct.h>
@@ -387,6 +388,7 @@ vm_thread_new(struct thread *td, int pages)
        td->td_kstack = ks;
        td->td_kstack_pages = pages;
        kasan_mark((void *)ks, ptoa(pages), ptoa(pages), 0);
+       kmsan_mark((void *)ks, ptoa(pages), KMSAN_STATE_UNINIT);
        return (1);
 }
 
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "[email protected]"

Reply via email to