git: 1be56e0bb1e8 - main - arm/unwind: Check stack pointer boundaries before dereferencing
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 27 Jul 2023 20:12:55 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=1be56e0bb1e8bd8373e446ff9386bcdd764935aa
commit 1be56e0bb1e8bd8373e446ff9386bcdd764935aa
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-07-27 19:44:00 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-07-27 19:44: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
---
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 bf8ffddfd2c2..5d3309d4539d 100644
--- a/sys/arm/arm/unwind.c
+++ b/sys/arm/arm/unwind.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/linker.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
#include <sys/queue.h>
#include <sys/systm.h>
@@ -370,6 +371,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;
@@ -404,6 +406,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;
@@ -430,6 +436,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;
@@ -437,6 +446,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++;
}
@@ -457,6 +468,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;
}