Module Name: src Committed By: christos Date: Sat Jul 20 18:25:11 UTC 2019
Modified Files: src/sys/arch/amd64/amd64: netbsd32_machdep.c process_machdep.c Log Message: Restore the ability to debug a 32 bit process from a 64 bit debugger: - add a function to validate a 64 bit context in 32 bit mode to write registers - remove 32 bit checks from read and write register functions - check for pc to fit in 32 bits. proposed in tech-kern, ok maxv. To generate a diff of this commit: cvs rdiff -u -r1.124 -r1.125 src/sys/arch/amd64/amd64/netbsd32_machdep.c cvs rdiff -u -r1.41 -r1.42 src/sys/arch/amd64/amd64/process_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/amd64/amd64/netbsd32_machdep.c diff -u src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.124 src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.125 --- src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.124 Wed Jun 26 08:30:12 2019 +++ src/sys/arch/amd64/amd64/netbsd32_machdep.c Sat Jul 20 14:25:11 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_machdep.c,v 1.124 2019/06/26 12:30:12 mgorny Exp $ */ +/* $NetBSD: netbsd32_machdep.c,v 1.125 2019/07/20 18:25:11 christos Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.124 2019/06/26 12:30:12 mgorny Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.125 2019/07/20 18:25:11 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -382,7 +382,7 @@ netbsd32_process_read_regs(struct lwp *l regs->r_esp = tf->tf_rsp & 0xffffffff; regs->r_ss = tf->tf_ss & 0xffff; - return (0); + return 0; } int @@ -987,6 +987,25 @@ cpu_mcontext32_validate(struct lwp *l, c return 0; } +static int +cpu_mcontext32from64_validate(struct lwp *l, const struct reg *regp) +{ + mcontext32_t mc; + __greg32_t *gr32 = mc.__gregs; + const __greg_t *gr = regp->regs; + + memset(&mc, 0, sizeof(mc)); + gr32[_REG32_EFL] = gr[_REG_RFLAGS]; + gr32[_REG32_EIP] = gr[_REG_RIP]; + gr32[_REG32_CS] = gr[_REG_CS]; + gr32[_REG32_DS] = gr[_REG_DS]; + gr32[_REG32_ES] = gr[_REG_ES]; + gr32[_REG32_FS] = gr[_REG_FS]; + gr32[_REG32_GS] = gr[_REG_GS]; + gr32[_REG32_SS] = gr[_REG_SS]; + return cpu_mcontext32_validate(l, &mc); +} + vaddr_t netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t sz, int topdown) @@ -1009,6 +1028,8 @@ netbsd32_machdep_md_init(void) { MODULE_HOOK_SET(netbsd32_machine32_hook, "mach32", netbsd32_machine32); + MODULE_HOOK_SET(netbsd32_reg_validate_hook, + "mcontext32from64_validate", cpu_mcontext32from64_validate); } void @@ -1016,4 +1037,5 @@ netbsd32_machdep_md_fini(void) { MODULE_HOOK_UNSET(netbsd32_machine32_hook); + MODULE_HOOK_UNSET(netbsd32_reg_validate_hook); } Index: src/sys/arch/amd64/amd64/process_machdep.c diff -u src/sys/arch/amd64/amd64/process_machdep.c:1.41 src/sys/arch/amd64/amd64/process_machdep.c:1.42 --- src/sys/arch/amd64/amd64/process_machdep.c:1.41 Wed Jun 26 21:59:30 2019 +++ src/sys/arch/amd64/amd64/process_machdep.c Sat Jul 20 14:25:11 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: process_machdep.c,v 1.41 2019/06/27 01:59:30 christos Exp $ */ +/* $NetBSD: process_machdep.c,v 1.42 2019/07/20 18:25:11 christos Exp $ */ /* * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. @@ -74,7 +74,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.41 2019/06/27 01:59:30 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.42 2019/07/20 18:25:11 christos Exp $"); #include "opt_xen.h" #include <sys/param.h> @@ -83,6 +83,7 @@ __KERNEL_RCSID(0, "$NetBSD: process_mach #include <sys/kernel.h> #include <sys/proc.h> #include <sys/ptrace.h> +#include <sys/compat_stub.h> #include <uvm/uvm_extern.h> @@ -103,42 +104,48 @@ process_frame(struct lwp *l) } int -process_read_regs(struct lwp *l, struct reg *regs) +process_read_regs(struct lwp *l, struct reg *regp) { struct trapframe *tf = process_frame(l); - struct proc *p = l->l_proc; + long *regs = regp->regs; + const bool pk32 = (l->l_proc->p_flag & PK_32) != 0; - if (p->p_flag & PK_32) { - return EINVAL; - } - - regs->regs[_REG_RDI] = tf->tf_rdi; - regs->regs[_REG_RSI] = tf->tf_rsi; - regs->regs[_REG_RDX] = tf->tf_rdx; - regs->regs[_REG_R10] = tf->tf_r10; - regs->regs[_REG_R8] = tf->tf_r8; - regs->regs[_REG_R9] = tf->tf_r9; + regs[_REG_RDI] = tf->tf_rdi; + regs[_REG_RSI] = tf->tf_rsi; + regs[_REG_RDX] = tf->tf_rdx; + regs[_REG_R10] = tf->tf_r10; + regs[_REG_R8] = tf->tf_r8; + regs[_REG_R9] = tf->tf_r9; /* argX not touched */ - regs->regs[_REG_RCX] = tf->tf_rcx; - regs->regs[_REG_R11] = tf->tf_r11; - regs->regs[_REG_R12] = tf->tf_r12; - regs->regs[_REG_R13] = tf->tf_r13; - regs->regs[_REG_R14] = tf->tf_r14; - regs->regs[_REG_R15] = tf->tf_r15; - regs->regs[_REG_RBP] = tf->tf_rbp; - regs->regs[_REG_RBX] = tf->tf_rbx; - regs->regs[_REG_RAX] = tf->tf_rax; - regs->regs[_REG_GS] = 0; - regs->regs[_REG_FS] = 0; - regs->regs[_REG_ES] = GSEL(GUDATA_SEL, SEL_UPL); - regs->regs[_REG_DS] = GSEL(GUDATA_SEL, SEL_UPL); - regs->regs[_REG_TRAPNO] = tf->tf_trapno; - regs->regs[_REG_ERR] = tf->tf_err; - regs->regs[_REG_RIP] = tf->tf_rip; - regs->regs[_REG_CS] = LSEL(LUCODE_SEL, SEL_UPL); - regs->regs[_REG_RFLAGS] = tf->tf_rflags; - regs->regs[_REG_RSP] = tf->tf_rsp; - regs->regs[_REG_SS] = LSEL(LUDATA_SEL, SEL_UPL); + regs[_REG_RCX] = tf->tf_rcx; + regs[_REG_R11] = tf->tf_r11; + regs[_REG_R12] = tf->tf_r12; + regs[_REG_R13] = tf->tf_r13; + regs[_REG_R14] = tf->tf_r14; + regs[_REG_R15] = tf->tf_r15; + regs[_REG_RBP] = tf->tf_rbp; + regs[_REG_RBX] = tf->tf_rbx; + regs[_REG_RAX] = tf->tf_rax; + if (pk32) { + regs[_REG_GS] = tf->tf_gs & 0xffff; + regs[_REG_FS] = tf->tf_fs & 0xffff; + regs[_REG_ES] = tf->tf_es & 0xffff; + regs[_REG_DS] = tf->tf_ds & 0xffff; + regs[_REG_CS] = tf->tf_cs & 0xffff; + regs[_REG_SS] = tf->tf_ss & 0xffff; + } else { + regs[_REG_GS] = 0; + regs[_REG_FS] = 0; + regs[_REG_ES] = GSEL(GUDATA_SEL, SEL_UPL); + regs[_REG_DS] = GSEL(GUDATA_SEL, SEL_UPL); + regs[_REG_CS] = LSEL(LUCODE_SEL, SEL_UPL); + regs[_REG_SS] = LSEL(LUDATA_SEL, SEL_UPL); + } + regs[_REG_TRAPNO] = tf->tf_trapno; + regs[_REG_ERR] = tf->tf_err; + regs[_REG_RIP] = tf->tf_rip; + regs[_REG_RFLAGS] = tf->tf_rflags; + regs[_REG_RSP] = tf->tf_rsp; return 0; } @@ -146,11 +153,6 @@ process_read_regs(struct lwp *l, struct int process_read_fpregs(struct lwp *l, struct fpreg *regs, size_t *sz) { - struct proc *p = l->l_proc; - - if (p->p_flag & PK_32) { - return EINVAL; - } process_read_fpregs_xmm(l, ®s->fxstate); @@ -160,11 +162,6 @@ process_read_fpregs(struct lwp *l, struc int process_read_dbregs(struct lwp *l, struct dbreg *regs, size_t *sz) { - struct proc *p = l->l_proc; - - if (p->p_flag & PK_32) { - return EINVAL; - } x86_dbregs_read(l, regs); @@ -175,19 +172,20 @@ int process_write_regs(struct lwp *l, const struct reg *regp) { struct trapframe *tf = process_frame(l); - struct proc *p = l->l_proc; int error; const long *regs = regp->regs; - - if (p->p_flag & PK_32) { - return EINVAL; - } + const bool pk32 = (l->l_proc->p_flag & PK_32) != 0; /* * Check for security violations. Note that struct regs is compatible * with the __gregs array in mcontext_t. */ - error = cpu_mcontext_validate(l, (const mcontext_t *)regs); + if (pk32) { + MODULE_HOOK_CALL(netbsd32_reg_validate_hook, (l, regp), EINVAL, + error); + } else { + error = cpu_mcontext_validate(l, (const mcontext_t *)regs); + } if (error != 0) return error; @@ -207,16 +205,25 @@ process_write_regs(struct lwp *l, const tf->tf_rbp = regs[_REG_RBP]; tf->tf_rbx = regs[_REG_RBX]; tf->tf_rax = regs[_REG_RAX]; - tf->tf_gs = 0; - tf->tf_fs = 0; - tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); - tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); + if (pk32) { + tf->tf_gs = regs[_REG_GS] & 0xffff; + tf->tf_fs = regs[_REG_FS] & 0xffff; + tf->tf_es = regs[_REG_ES] & 0xffff; + tf->tf_ds = regs[_REG_DS] & 0xffff; + tf->tf_cs = regs[_REG_CS] & 0xffff; + tf->tf_ss = regs[_REG_SS] & 0xffff; + } else { + tf->tf_gs = 0; + tf->tf_fs = 0; + tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); + tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); + tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL); + tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL); + } /* trapno, err not touched */ tf->tf_rip = regs[_REG_RIP]; - tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL); tf->tf_rflags = regs[_REG_RFLAGS]; tf->tf_rsp = regs[_REG_RSP]; - tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL); #ifdef XENPV /* see comment in cpu_setmcontext */ @@ -230,11 +237,6 @@ process_write_regs(struct lwp *l, const int process_write_fpregs(struct lwp *l, const struct fpreg *regs, size_t sz) { - struct proc *p = l->l_proc; - - if (p->p_flag & PK_32) { - return EINVAL; - } process_write_fpregs_xmm(l, ®s->fxstate); return 0; @@ -243,13 +245,8 @@ process_write_fpregs(struct lwp *l, cons int process_write_dbregs(struct lwp *l, const struct dbreg *regs, size_t sz) { - struct proc *p = l->l_proc; int error; - if (p->p_flag & PK_32) { - return EINVAL; - } - /* * Check for security violations. */ @@ -279,15 +276,12 @@ int process_set_pc(struct lwp *l, void *addr) { struct trapframe *tf = process_frame(l); - struct proc *p = l->l_proc; - - if (p->p_flag & PK_32) { - return EINVAL; - } + const bool pk32 = (l->l_proc->p_flag & PK_32) != 0; + const uint64_t rip = (uint64_t)addr; - if ((uint64_t)addr >= VM_MAXUSER_ADDRESS) + if (rip >= (pk32 ? VM_MAXUSER_ADDRESS32 : VM_MAXUSER_ADDRESS)) return EINVAL; - tf->tf_rip = (uint64_t)addr; + tf->tf_rip = rip; return 0; }