git: b0f71f1bc5a4 - main - amd64: Add MD bits for KMSAN

Mark Johnston markj at FreeBSD.org
Wed Aug 11 01:31:07 UTC 2021


The branch main has been updated by markj:

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

commit b0f71f1bc5a4b111523b73455fd012f54f7879f9
Author:     Mark Johnston <markj at FreeBSD.org>
AuthorDate: 2021-08-10 21:14:47 +0000
Commit:     Mark Johnston <markj at FreeBSD.org>
CommitDate: 2021-08-11 01:27:53 +0000

    amd64: Add MD bits for KMSAN
    
    Interrupt and exception handlers must call kmsan_intr_enter() prior to
    calling any C code.  This is because the KMSAN runtime maintains some
    TLS in order to track initialization state of function parameters and
    return values across function calls.  Then, to ensure that this state is
    kept consistent in the face of asynchronous kernel-mode excpeptions, the
    runtime uses a stack of TLS blocks, and kmsan_intr_enter() and
    kmsan_intr_leave() push and pop that stack, respectively.
    
    Use these functions in amd64 interrupt and exception handlers.  Note
    that handlers for user->kernel transitions need not be annotated.
    
    Also ensure that trap frames pushed by the CPU and by handlers are
    marked as initialized before they are used.
    
    Reviewed by:    kib
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D31467
---
 sys/amd64/amd64/apic_vector.S  | 22 ++++++++++++++++++++++
 sys/amd64/amd64/atpic_vector.S |  2 ++
 sys/amd64/amd64/exception.S    | 12 ++++++++++--
 sys/amd64/amd64/machdep.c      |  2 ++
 sys/amd64/amd64/trap.c         |  5 +++++
 sys/amd64/ia32/ia32_syscall.c  |  3 +++
 sys/amd64/include/asmacros.h   | 22 ++++++++++++++++++++++
 sys/kern/kern_fork.c           |  2 ++
 sys/kern/subr_trap.c           |  3 +++
 sys/x86/isa/atpic.c            |  3 ++-
 sys/x86/x86/local_apic.c       |  6 ++++--
 11 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index 21696a93fc5f..cea9b79a0ec8 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -81,6 +81,7 @@ as_lapic_eoi:
  */
 	.macro	ISR_VEC	index, vec_name
 	INTR_HANDLER	\vec_name
+	KMSAN_ENTER
 	cmpl	$0,x2apic_mode
 	je	1f
 	movl	$(MSR_APIC_ISR0 + \index),%ecx
@@ -97,6 +98,7 @@ as_lapic_eoi:
 	movl	%eax, %edi	/* pass the IRQ */
 	call	lapic_handle_intr
 3:
+	KMSAN_LEAVE
 	jmp	doreti
 	.endm
 
@@ -125,22 +127,28 @@ IDTVEC(spuriousint)
  * Local APIC periodic timer handler.
  */
 	INTR_HANDLER	timerint
+	KMSAN_ENTER
 	movq	%rsp, %rdi
 	call	lapic_handle_timer
+	KMSAN_LEAVE
 	jmp	doreti
 
 /*
  * Local APIC CMCI handler.
  */
 	INTR_HANDLER cmcint
+	KMSAN_ENTER
 	call	lapic_handle_cmc
+	KMSAN_LEAVE
 	jmp	doreti
 
 /*
  * Local APIC error interrupt handler.
  */
 	INTR_HANDLER errorint
+	KMSAN_ENTER
 	call	lapic_handle_error
+	KMSAN_LEAVE
 	jmp	doreti
 
 #ifdef XENHVM
@@ -149,8 +157,10 @@ IDTVEC(spuriousint)
  * Only used when the hypervisor supports direct vector callbacks.
  */
 	INTR_HANDLER xen_intr_upcall
+	KMSAN_ENTER
 	movq	%rsp, %rdi
 	call	xen_intr_handle_upcall
+	KMSAN_LEAVE
 	jmp	doreti
 #endif
 
@@ -165,8 +175,10 @@ IDTVEC(spuriousint)
  * IPI handler for cache and TLB shootdown
  */
 	INTR_HANDLER invlop
+	KMSAN_ENTER
 	call	invlop_handler
 	call	as_lapic_eoi
+	KMSAN_LEAVE
 	jmp	ld_regs
 
 /*
@@ -174,7 +186,9 @@ IDTVEC(spuriousint)
  */
 	INTR_HANDLER ipi_intr_bitmap_handler
 	call	as_lapic_eoi
+	KMSAN_ENTER
 	call	ipi_bitmap_handler
+	KMSAN_LEAVE
 	jmp	doreti
 
 /*
@@ -182,15 +196,19 @@ IDTVEC(spuriousint)
  */
 	INTR_HANDLER cpustop
 	call	as_lapic_eoi
+	KMSAN_ENTER
 	call	cpustop_handler
+	KMSAN_LEAVE
 	jmp	doreti
 
 /*
  * Executed by a CPU when it receives an IPI_SUSPEND from another CPU.
  */
 	INTR_HANDLER cpususpend
+	KMSAN_ENTER
 	call	cpususpend_handler
 	call	as_lapic_eoi
+	KMSAN_LEAVE
 	jmp	doreti
 
 /*
@@ -198,7 +216,9 @@ IDTVEC(spuriousint)
  */
 	INTR_HANDLER ipi_swi
 	call	as_lapic_eoi
+	KMSAN_ENTER
 	call	ipi_swi_handler
+	KMSAN_LEAVE
 	jmp	doreti
 
 /*
@@ -212,8 +232,10 @@ IDTVEC(spuriousint)
 	movq	ipi_rendezvous_counts(,%rax,8), %rax
 	incq	(%rax)
 #endif
+	KMSAN_ENTER
 	call	smp_rendezvous_action
 	call	as_lapic_eoi
+	KMSAN_LEAVE
 	jmp	doreti
 
 /*
diff --git a/sys/amd64/amd64/atpic_vector.S b/sys/amd64/amd64/atpic_vector.S
index d76331a887ad..c6471999c238 100644
--- a/sys/amd64/amd64/atpic_vector.S
+++ b/sys/amd64/amd64/atpic_vector.S
@@ -44,9 +44,11 @@
  */
 	.macro	INTR	irq_num, vec_name
 	INTR_HANDLER	\vec_name
+	KMSAN_ENTER
 	movq	%rsp, %rsi
 	movl	$\irq_num, %edi	 	/* pass the IRQ */
 	call	atpic_handle_intr
+	KMSAN_LEAVE
 	jmp	doreti
 	.endm
 
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index 4716ca8cd7c2..d1e49faa40e7 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -282,8 +282,10 @@ alltraps_pushregs_no_rax:
 	.globl	calltrap
 	.type	calltrap, at function
 calltrap:
-	movq	%rsp,%rdi
+	KMSAN_ENTER
+	movq	%rsp, %rdi
 	call	trap_check
+	KMSAN_LEAVE
 	jmp	doreti			/* Handle any pending ASTs */
 
 	/*
@@ -352,8 +354,10 @@ IDTVEC(dblfault)
 	cmpq	$~0,%rax
 	je	2f
 	movq	%rax,%cr3
-2:	movq	%rsp,%rdi
+2:	KMSAN_ENTER
+	movq	%rsp,%rdi
 	call	dblfault_handler
+	KMSAN_LEAVE
 3:	hlt
 	jmp	3b
 
@@ -856,8 +860,10 @@ nmi_fromuserspace:
 3:
 /* Note: this label is also used by ddb and gdb: */
 nmi_calltrap:
+	KMSAN_ENTER
 	movq	%rsp,%rdi
 	call	trap
+	KMSAN_LEAVE
 #ifdef HWPMC_HOOKS
 	/*
 	 * Capture a userspace callchain if needed.
@@ -1043,8 +1049,10 @@ mchk_fromuserspace:
 1:	call	handle_ibrs_entry
 /* Note: this label is also used by ddb and gdb: */
 mchk_calltrap:
+	KMSAN_ENTER
 	movq	%rsp,%rdi
 	call	mca_intr
+	KMSAN_LEAVE
 	testl	%ebx,%ebx	/* %ebx != 0 => return to userland */
 	jnz	doreti_exit
 	/*
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 8599dc2fa8f6..e49dcaa576e8 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/memrange.h>
+#include <sys/msan.h>
 #include <sys/msgbuf.h>
 #include <sys/mutex.h>
 #include <sys/pcpu.h>
@@ -1943,6 +1944,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 	thread0.td_critnest = 0;
 
 	kasan_init();
+	kmsan_init();
 
 	TSEXIT();
 
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index b08495f3f139..ff4bccebed5b 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/ktr.h>
 #include <sys/lock.h>
+#include <sys/msan.h>
 #include <sys/mutex.h>
 #include <sys/resourcevar.h>
 #include <sys/signalvar.h>
@@ -229,6 +230,7 @@ trap(struct trapframe *frame)
 	dr6 = 0;
 
 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
+	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
 
 	VM_CNT_INC(v_trap);
 	type = frame->tf_trapno;
@@ -973,6 +975,7 @@ trap_user_dtrace(struct trapframe *frame, int (**hookp)(struct trapframe *))
 void
 dblfault_handler(struct trapframe *frame)
 {
+	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
 #ifdef KDTRACE_HOOKS
 	if (dtrace_doubletrap_func != NULL)
 		(*dtrace_doubletrap_func)();
@@ -1177,6 +1180,8 @@ amd64_syscall(struct thread *td, int traced)
 {
 	ksiginfo_t ksi;
 
+	kmsan_mark(td->td_frame, sizeof(*td->td_frame), KMSAN_STATE_INITED);
+
 #ifdef DIAGNOSTIC
 	if (!TRAPF_USERMODE(td->td_frame)) {
 		panic("syscall");
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
index 9294ef8ce741..4e95d056d7fa 100644
--- a/sys/amd64/ia32/ia32_syscall.c
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/ktr.h>
 #include <sys/lock.h>
+#include <sys/msan.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/ptrace.h>
@@ -208,6 +209,8 @@ ia32_syscall(struct trapframe *frame)
 	register_t orig_tf_rflags;
 	ksiginfo_t ksi;
 
+	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
+
 	orig_tf_rflags = frame->tf_rflags;
 	td = curthread;
 	td->td_frame = frame;
diff --git a/sys/amd64/include/asmacros.h b/sys/amd64/include/asmacros.h
index 438f4ec26f61..973a1c761c6b 100644
--- a/sys/amd64/include/asmacros.h
+++ b/sys/amd64/include/asmacros.h
@@ -213,6 +213,28 @@ X\vec_name:
 	movq	TF_R15(%rsp),%r15
 	.endm
 
+#ifdef KMSAN
+/*
+ * The KMSAN runtime relies on a TLS block to track initialization and origin
+ * state for function parameters and return values.  To keep this state
+ * consistent in the face of asynchronous kernel-mode traps, the runtime
+ * maintains a stack of blocks: when handling an exception or interrupt,
+ * kmsan_intr_enter() pushes the new block to be used until the handler is
+ * complete, at which point kmsan_intr_leave() restores the previous block.
+ *
+ * Thus, KMSAN_ENTER/LEAVE hooks are required only in handlers for events that
+ * may have happened while in kernel-mode.  In particular, they are not required
+ * around amd64_syscall() or ast() calls.  Otherwise, kmsan_intr_enter() can be
+ * called unconditionally, without distinguishing between entry from user-mode
+ * or kernel-mode.
+ */
+#define	KMSAN_ENTER	callq kmsan_intr_enter
+#define	KMSAN_LEAVE	callq kmsan_intr_leave
+#else
+#define	KMSAN_ENTER
+#define	KMSAN_LEAVE
+#endif
+
 #endif /* LOCORE */
 
 #ifdef __STDC__
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index b71a00adb62e..7b8a95333868 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1057,6 +1057,8 @@ fork_exit(void (*callout)(void *, struct trapframe *), void *arg,
 	struct thread *td;
 	struct thread *dtd;
 
+	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
+
 	td = curthread;
 	p = td->td_proc;
 	KASSERT(p->p_state == PRS_NORMAL, ("executing process is still new"));
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index d0f616d037c5..edeeded09911 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/capsicum.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
+#include <sys/msan.h>
 #include <sys/mutex.h>
 #include <sys/pmckern.h>
 #include <sys/proc.h>
@@ -216,6 +217,8 @@ ast(struct trapframe *framep)
 	int flags, sig;
 	bool resched_sigs;
 
+	kmsan_mark(framep, sizeof(*framep), KMSAN_STATE_INITED);
+
 	td = curthread;
 	p = td->td_proc;
 
diff --git a/sys/x86/isa/atpic.c b/sys/x86/isa/atpic.c
index 28c10ee7009f..de72780c100b 100644
--- a/sys/x86/isa/atpic.c
+++ b/sys/x86/isa/atpic.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/module.h>
+#include <sys/msan.h>
 
 #include <machine/cpufunc.h>
 #include <machine/frame.h>
@@ -523,8 +524,8 @@ atpic_handle_intr(u_int vector, struct trapframe *frame)
 {
 	struct intsrc *isrc;
 
-	/* The frame may have been written into a poisoned region. */
 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
+	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
 
 	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
 	isrc = &atintrs[vector].at_intsrc;
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index 9708121e0829..04de3ae47461 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -48,6 +48,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/pcpu.h>
 #include <sys/proc.h>
@@ -1306,8 +1307,9 @@ lapic_handle_intr(int vector, struct trapframe *frame)
 {
 	struct intsrc *isrc;
 
-	/* The frame may have been written into a poisoned region. */
 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
+	kmsan_mark(&vector, sizeof(vector), KMSAN_STATE_INITED);
+	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
 
 	isrc = intr_lookup_source(apic_idt_to_irq(PCPU_GET(apic_id),
 	    vector));
@@ -1324,8 +1326,8 @@ lapic_handle_timer(struct trapframe *frame)
 	/* Send EOI first thing. */
 	lapic_eoi();
 
-	/* The frame may have been written into a poisoned region. */
 	kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
+	kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
 
 #if defined(SMP) && !defined(SCHED_ULE)
 	/*


More information about the dev-commits-src-all mailing list