Date: Wed, 11 Aug 2021 01:31:12 GMT From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 100949103a63 - main - uma: Add KMSAN hooks Message-ID: <202108110131.17B1VC0L051185@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=100949103a6340aff8a6a4caf1927374c242721c commit 100949103a6340aff8a6a4caf1927374c242721c Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2021-08-10 21:15:03 +0000 Commit: Mark Johnston <markj@FreeBSD.org> 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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202108110131.17B1VC0L051185>