svn commit: r368240 - in head/sys: cddl/dev/dtrace/amd64 cddl/dev/dtrace/i386 ddb riscv/riscv sys x86/x86

John Baldwin jhb at FreeBSD.org
Tue Dec 1 17:04:48 UTC 2020


Author: jhb
Date: Tue Dec  1 17:04:46 2020
New Revision: 368240
URL: https://svnweb.freebsd.org/changeset/base/368240

Log:
  Add a kstack_contains() helper function.
  
  This is useful for stack unwinders which need to avoid out-of-bounds
  reads of a kernel stack which can trigger kernel faults.
  
  Reviewed by:	kib, markj
  Obtained from:	CheriBSD
  Sponsored by:	DARPA
  Differential Revision:	https://reviews.freebsd.org/D27356

Modified:
  head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c
  head/sys/cddl/dev/dtrace/i386/dtrace_isa.c
  head/sys/ddb/db_ps.c
  head/sys/riscv/riscv/stack_machdep.c
  head/sys/sys/proc.h
  head/sys/x86/x86/stack_machdep.c

Modified: head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c
==============================================================================
--- head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c	Tue Dec  1 16:44:36 2020	(r368239)
+++ head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c	Tue Dec  1 17:04:46 2020	(r368240)
@@ -73,14 +73,10 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, in
 	frame = (struct amd64_frame *)rbp;
 	td = curthread;
 	while (depth < pcstack_limit) {
-		if (!INKERNEL((long) frame))
+		if (!kstack_contains(curthread, (vm_offset_t)frame,
+		    sizeof(*frame))
 			break;
 
-		if ((vm_offset_t)frame >=
-		    td->td_kstack + ptoa(td->td_kstack_pages) ||
-		    (vm_offset_t)frame < td->td_kstack)
-			break;
-
 		callpc = frame->f_retaddr;
 
 		if (!INKERNEL(callpc))
@@ -466,14 +462,11 @@ dtrace_getstackdepth(int aframes)
 	frame = (struct amd64_frame *)rbp;
 	depth++;
 	for(;;) {
-		if (!INKERNEL((long) frame))
+		if (!kstack_contains(curthread, (vm_offset_t)frame,
+		    sizeof(*frame))
 			break;
-		if (!INKERNEL((long) frame->f_frame))
-			break;
 		depth++;
-		if (frame->f_frame <= frame ||
-		    (vm_offset_t)frame->f_frame >= curthread->td_kstack +
-		    curthread->td_kstack_pages * PAGE_SIZE)
+		if (frame->f_frame <= frame)
 			break;
 		frame = frame->f_frame;
 	}

Modified: head/sys/cddl/dev/dtrace/i386/dtrace_isa.c
==============================================================================
--- head/sys/cddl/dev/dtrace/i386/dtrace_isa.c	Tue Dec  1 16:44:36 2020	(r368239)
+++ head/sys/cddl/dev/dtrace/i386/dtrace_isa.c	Tue Dec  1 17:04:46 2020	(r368240)
@@ -73,7 +73,8 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, in
 
 	frame = (struct i386_frame *)ebp;
 	while (depth < pcstack_limit) {
-		if (!INKERNEL(frame))
+		if (!kstack_contains(curthread, (vm_offset_t)frame,
+		    sizeof(*frame))
 			break;
 
 		callpc = frame->f_retaddr;
@@ -91,9 +92,7 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, in
 			pcstack[depth++] = callpc;
 		}
 
-		if (frame->f_frame <= frame ||
-		    (vm_offset_t)frame->f_frame >= curthread->td_kstack +
-		    curthread->td_kstack_pages * PAGE_SIZE)
+		if (frame->f_frame <= frame)
 			break;
 		frame = frame->f_frame;
 	}
@@ -484,14 +483,10 @@ dtrace_getstackdepth(int aframes)
 	frame = (struct i386_frame *)ebp;
 	depth++;
 	for(;;) {
-		if (!INKERNEL((long) frame))
+		if (!kstack_contains((vm_offset_t)frame, sizeof(*frame))
 			break;
-		if (!INKERNEL((long) frame->f_frame))
-			break;
 		depth++;
-		if (frame->f_frame <= frame ||
-		    (vm_offset_t)frame->f_frame >= curthread->td_kstack +
-		    curthread->td_kstack_pages * PAGE_SIZE)
+		if (frame->f_frame <= frame)
 			break;
 		frame = frame->f_frame;
 	}

Modified: head/sys/ddb/db_ps.c
==============================================================================
--- head/sys/ddb/db_ps.c	Tue Dec  1 16:44:36 2020	(r368239)
+++ head/sys/ddb/db_ps.c	Tue Dec  1 17:04:46 2020	(r368240)
@@ -527,8 +527,7 @@ db_findstack_cmd(db_expr_t addr, bool have_addr, db_ex
 
 	FOREACH_PROC_IN_SYSTEM(p) {
 		FOREACH_THREAD_IN_PROC(p, td) {
-			if (td->td_kstack <= saddr && saddr < td->td_kstack +
-			    PAGE_SIZE * td->td_kstack_pages) {
+			if (kstack_contains(td, saddr, 1)) {
 				db_printf("Thread %p\n", td);
 				return;
 			}

Modified: head/sys/riscv/riscv/stack_machdep.c
==============================================================================
--- head/sys/riscv/riscv/stack_machdep.c	Tue Dec  1 16:44:36 2020	(r368239)
+++ head/sys/riscv/riscv/stack_machdep.c	Tue Dec  1 17:04:46 2020	(r368240)
@@ -53,9 +53,8 @@ stack_capture(struct thread *td, struct stack *st, str
 	stack_zero(st);
 
 	while (1) {
-		if ((vm_offset_t)frame->fp < td->td_kstack ||
-		    (vm_offset_t)frame->fp >= td->td_kstack +
-		    td->td_kstack_pages * PAGE_SIZE)
+		if (!kstack_contains(td, (vm_offset_t)frame->fp -
+		    (sizeof(uintptr_t) * 2), sizeof(uintptr_t) * 2))
 			break;
 		unwind_frame(frame);
 		if (!INKERNEL((vm_offset_t)frame->pc))

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Tue Dec  1 16:44:36 2020	(r368239)
+++ head/sys/sys/proc.h	Tue Dec  1 17:04:46 2020	(r368240)
@@ -1198,6 +1198,13 @@ curthread_pflags2_restore(int save)
 	curthread->td_pflags2 &= save;
 }
 
+static __inline bool
+kstack_contains(struct thread *td, vm_offset_t va, size_t len)
+{
+	return (va >= td->td_kstack && va + len >= va &&
+	    va + len <= td->td_kstack + td->td_kstack_pages * PAGE_SIZE);
+}
+
 static __inline __pure2 struct td_sched *
 td_get_sched(struct thread *td)
 {

Modified: head/sys/x86/x86/stack_machdep.c
==============================================================================
--- head/sys/x86/x86/stack_machdep.c	Tue Dec  1 16:44:36 2020	(r368239)
+++ head/sys/x86/x86/stack_machdep.c	Tue Dec  1 17:04:46 2020	(r368240)
@@ -79,9 +79,7 @@ stack_capture(struct thread *td, struct stack *st, reg
 	stack_zero(st);
 	frame = (x86_frame_t)fp;
 	while (1) {
-		if ((vm_offset_t)frame < td->td_kstack ||
-		    (vm_offset_t)frame >= td->td_kstack +
-		    td->td_kstack_pages * PAGE_SIZE)
+		if (!kstack_contains(td, (vm_offset_t)frame, sizeof(*frame)))
 			break;
 		callpc = frame->f_retaddr;
 		if (!INKERNEL(callpc))


More information about the svn-src-head mailing list