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