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, &regs->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, &regs->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;
 }

Reply via email to