git: d0434eff5786 - stable/13 - arm/unwind: Check stack pointer boundaries before dereferencing
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 24 Aug 2023 13:41:09 UTC
The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=d0434eff57861d0fbff6e31ea541c08979c99428 commit d0434eff57861d0fbff6e31ea541c08979c99428 Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2023-07-27 19:44:00 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2023-08-24 13:33:00 +0000 arm/unwind: Check stack pointer boundaries before dereferencing If the unwinder somehow ends up with a stack pointer that lies outside the stack, then an attempt to dereference can lead to a fault, which causes the kernel to panic again and unwind the stack, which leads to a fault... Add kstack_contains() checks at points where we dereference the stack pointer. This avoids the aforementioned infinite loop in one case I hit where some OpenSSL assembly code apparently confuses the unwinder. Reviewed by: jhb MFC after: 2 weeks Sponsored by: Klara, Inc. Sponsored by: Stormshield Differential Revision: https://reviews.freebsd.org/D41210 (cherry picked from commit 1be56e0bb1e8bd8373e446ff9386bcdd764935aa) --- sys/arm/arm/unwind.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sys/arm/arm/unwind.c b/sys/arm/arm/unwind.c index 4a24d8f13fb1..cdc9ef225ee7 100644 --- a/sys/arm/arm/unwind.c +++ b/sys/arm/arm/unwind.c @@ -33,6 +33,7 @@ #include <sys/kernel.h> #include <sys/linker.h> #include <sys/malloc.h> +#include <sys/proc.h> #include <sys/queue.h> #include <sys/systm.h> @@ -368,6 +369,7 @@ unwind_exec_read_byte(struct unwind_state *state) static int unwind_exec_insn(struct unwind_state *state) { + struct thread *td = curthread; unsigned int insn; uint32_t *vsp = (uint32_t *)state->registers[SP]; int update_vsp = 0; @@ -402,6 +404,10 @@ unwind_exec_insn(struct unwind_state *state) /* Load the registers */ for (reg = 4; mask && reg < 16; mask >>= 1, reg++) { if (mask & 1) { + if (!kstack_contains(td, (uintptr_t)vsp, + sizeof(*vsp))) + return 1; + state->registers[reg] = *vsp++; state->update_mask |= 1 << reg; @@ -428,6 +434,9 @@ unwind_exec_insn(struct unwind_state *state) update_vsp = 1; /* Pop the registers */ + if (!kstack_contains(td, (uintptr_t)vsp, + sizeof(*vsp) * (4 + count))) + return 1; for (reg = 4; reg <= 4 + count; reg++) { state->registers[reg] = *vsp++; state->update_mask |= 1 << reg; @@ -435,6 +444,8 @@ unwind_exec_insn(struct unwind_state *state) /* Check if we are in the pop r14 version */ if ((insn & INSN_POP_TYPE_MASK) != 0) { + if (!kstack_contains(td, (uintptr_t)vsp, sizeof(*vsp))) + return 1; state->registers[14] = *vsp++; } @@ -455,6 +466,9 @@ unwind_exec_insn(struct unwind_state *state) /* Load the registers */ for (reg = 0; mask && reg < 4; mask >>= 1, reg++) { if (mask & 1) { + if (!kstack_contains(td, (uintptr_t)vsp, + sizeof(*vsp))) + return 1; state->registers[reg] = *vsp++; state->update_mask |= 1 << reg; }