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))
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to