diff options
author | Mark Johnston <markj@FreeBSD.org> | 2024-02-08 15:57:36 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2024-02-08 16:35:11 +0000 |
commit | c05d7bdaf63dff2dede5aee742aeb8b1455e40d5 (patch) | |
tree | 2dfc80c6c41c99083080e2b8aaa953dfd7406d3e | |
parent | 52bf6257c2aac19788636e525b139ec57a38fb1c (diff) | |
download | src-c05d7bdaf63dff2dede5aee742aeb8b1455e40d5.tar.gz src-c05d7bdaf63dff2dede5aee742aeb8b1455e40d5.zip |
arm64: Make KMSAN aware of exceptions
- Call kmsan_intr_enter() when an exception occurs. This ensures that
code running in the exception context does not clobber thread-local
KMSAN state.
- Ensure that stack memory containing trap frames is treated as
initialized.
Co-authored-by: Alexander Stetsenko <alex.stetsenko@klarasystems.com>
Reviewed by: imp
MFC after: 2 weeks
Sponsored by: Klara, Inc.
Sponsored by: Juniper Networks, Inc.
Differential Revision: https://reviews.freebsd.org/D43155
-rw-r--r-- | sys/arm64/arm64/exception.S | 34 | ||||
-rw-r--r-- | sys/arm64/arm64/trap.c | 9 | ||||
-rw-r--r-- | sys/kern/subr_intr.c | 2 |
3 files changed, 45 insertions, 0 deletions
diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S index b1990fc71281..bab71fed4453 100644 --- a/sys/arm64/arm64/exception.S +++ b/sys/arm64/arm64/exception.S @@ -193,55 +193,89 @@ 2: .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 bl kmsan_intr_enter +#define KMSAN_LEAVE bl kmsan_intr_leave +#else +#define KMSAN_ENTER +#define KMSAN_LEAVE +#endif + ENTRY(handle_el1h_sync) save_registers 1 + KMSAN_ENTER ldr x0, [x18, #PC_CURTHREAD] mov x1, sp bl do_el1h_sync + KMSAN_LEAVE restore_registers 1 ERET END(handle_el1h_sync) ENTRY(handle_el1h_irq) save_registers 1 + KMSAN_ENTER mov x0, sp bl intr_irq_handler + KMSAN_LEAVE restore_registers 1 ERET END(handle_el1h_irq) ENTRY(handle_el0_sync) save_registers 0 + KMSAN_ENTER ldr x0, [x18, #PC_CURTHREAD] mov x1, sp str x1, [x0, #TD_FRAME] bl do_el0_sync do_ast + KMSAN_LEAVE restore_registers 0 ERET END(handle_el0_sync) ENTRY(handle_el0_irq) save_registers 0 + KMSAN_ENTER mov x0, sp bl intr_irq_handler do_ast + KMSAN_LEAVE restore_registers 0 ERET END(handle_el0_irq) ENTRY(handle_serror) save_registers 0 + KMSAN_ENTER mov x0, sp 1: bl do_serror b 1b + KMSAN_LEAVE END(handle_serror) ENTRY(handle_empty_exception) save_registers 0 + KMSAN_ENTER mov x0, sp 1: bl unhandled_exception b 1b + KMSAN_LEAVE END(handle_empty_exception) .macro vector name, el diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index 03cac1e6450e..c0066ae7dcad 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -33,6 +33,7 @@ #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> @@ -478,6 +479,8 @@ do_el1h_sync(struct thread *td, struct trapframe *frame) int dfsc; kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0); + kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED); + far = frame->tf_far; /* Read the esr register to get the exception details */ esr = frame->tf_esr; @@ -591,6 +594,8 @@ do_el0_sync(struct thread *td, struct trapframe *frame) get_pcpu(), READ_SPECIALREG(tpidr_el1))); kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0); + kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED); + far = frame->tf_far; esr = frame->tf_esr; exception = ESR_ELx_EXCEPTION(esr); @@ -737,6 +742,8 @@ do_serror(struct trapframe *frame) uint64_t esr, far; kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0); + kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED); + far = frame->tf_far; esr = frame->tf_esr; @@ -752,6 +759,8 @@ unhandled_exception(struct trapframe *frame) uint64_t esr, far; kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0); + kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED); + far = frame->tf_far; esr = frame->tf_esr; diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c index a03607c781b2..5958f9025b27 100644 --- a/sys/kern/subr_intr.c +++ b/sys/kern/subr_intr.c @@ -54,6 +54,7 @@ #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> +#include <sys/msan.h> #include <sys/mutex.h> #include <sys/proc.h> #include <sys/queue.h> @@ -334,6 +335,7 @@ intr_irq_handler(struct trapframe *tf) KASSERT(irq_root_filter != NULL, ("%s: no filter", __func__)); kasan_mark(tf, sizeof(*tf), sizeof(*tf), 0); + kmsan_mark(tf, sizeof(*tf), KMSAN_STATE_INITED); VM_CNT_INC(v_intr); critical_enter(); |