From owner-dev-commits-src-all@freebsd.org Wed Aug 11 01:31:12 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CCFED6723E1; Wed, 11 Aug 2021 01:31:12 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4GksjD3rrHz3Pn5; Wed, 11 Aug 2021 01:31:12 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4A18726508; Wed, 11 Aug 2021 01:31:12 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 17B1VC1I051186; Wed, 11 Aug 2021 01:31:12 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 17B1VC0L051185; Wed, 11 Aug 2021 01:31:12 GMT (envelope-from git) Date: Wed, 11 Aug 2021 01:31:12 GMT Message-Id: <202108110131.17B1VC0L051185@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 100949103a63 - main - uma: Add KMSAN hooks MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 100949103a6340aff8a6a4caf1927374c242721c Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 Aug 2021 01:31:13 -0000 The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=100949103a6340aff8a6a4caf1927374c242721c commit 100949103a6340aff8a6a4caf1927374c242721c Author: Mark Johnston AuthorDate: 2021-08-10 21:15:03 +0000 Commit: Mark Johnston 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 #include #include +#include #include #include #include @@ -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 #include #include -#include +#include #include #include #include @@ -79,6 +79,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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 #include #include +#include #include #include #include @@ -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); }