NetBSD Problem Report #51514

From www@NetBSD.org  Wed Sep 28 10:04:14 2016
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 082337A26F
	for <gnats-bugs@gnats.NetBSD.org>; Wed, 28 Sep 2016 10:04:14 +0000 (UTC)
Message-Id: <20160928100412.380097A2C2@mollari.NetBSD.org>
Date: Wed, 28 Sep 2016 10:04:12 +0000 (UTC)
From: rokuyama@rk.phys.keio.ac.jp
Reply-To: rokuyama@rk.phys.keio.ac.jp
To: gnats-bugs@NetBSD.org
Subject: ptrace(2) fails for 32-bit process on 64-bit kernel
X-Send-Pr-Version: www-1.0

>Number:         51514
>Category:       kern
>Synopsis:       ptrace(2) fails for 32-bit process on 64-bit kernel
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    skrll
>State:          closed
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Sep 28 10:05:00 +0000 2016
>Closed-Date:    Sat Nov 05 08:14:59 +0000 2016
>Last-Modified:  Sat Nov 05 08:14:59 +0000 2016
>Originator:     Rin Okuyama
>Release:        7.99.39
>Organization:
Faculty of Science and Technology, Keio University
>Environment:
NetBSD erlite 7.99.39 NetBSD 7.99.39 (ERLITE_RO) #5: Wed Sep 28 06:43:08 JST 2016  rin@XXX:XXX evbmips
>Description:
ptrace(2) does not work properly for 32-bit process on 64-bit kernel with
COMPAT_NETBSD32 option. As a result, GDB (both 64-bit and 32-bit version)
fails for 32-bit binaries. For example, on sparc64 machine with base.tgz
and comp.tgz from sparc extracted into /emul/netbsd32:

  % /emul/netbsd32/usr/bin/cc -g -O0 hello.c
  % /emul/netbsd32/usr/bin/gdb ./a.out
  GNU gdb (GDB) 7.10.1
  ...snip...
  (gdb) r
  Starting program: /home/rin/a.out
  Hello, World!

Then, it hangs indefinitely with a.out being a zombie. I observed similar
results on amd64 and mips64. ( For mips64, I reported the problem here:
http://mail-index.netbsd.org/port-mips/2016/09/11/msg000759.html )
This is especially problematic for mips64, for which the default userland
ABI is N32.
>How-To-Repeat:
described above
>Fix:
I added COMPAT_NETBSD32 support to kern/sys_process.c (In my opinion,
it is easier to implement it to kern/sys_process.c, rather than to
netbsd32_ptrace(9) in compat/netbsd32/netbsd32_netbsd.c). This requires
new functions, process_write_regs32 and process_write_fpregs32 for archs
in which "struct reg" and "struct reg32" ("fpreg" and "fpreg32") are not
equivalent. I added them to sys/ptrace.h, and implemented for amd64 and
sparc64. Then, 32-bit version of GDB works fine for 32-bit binaries, and
64-bit version fails but terminates properly. I tested the patch on
amd64, sparc64, and mips64 (with N32 userland).

--- src/sys/arch/amd64/amd64/netbsd32_machdep.c.orig	2016-09-27 23:02:35.595062549 +0900
+++ src/sys/arch/amd64/amd64/netbsd32_machdep.c	2016-09-28 06:40:34.097335905 +0900
@@ -487,12 +487,12 @@
 {
 	struct trapframe *tf = l->l_md.md_regs;

-	regs->r_gs = LSEL(LUCODE32_SEL, SEL_UPL);
-	regs->r_fs = LSEL(LUCODE32_SEL, SEL_UPL);
-	regs->r_es = LSEL(LUCODE32_SEL, SEL_UPL);
-	regs->r_ds = LSEL(LUCODE32_SEL, SEL_UPL);
-	regs->r_eflags = tf->tf_rflags;
 	/* XXX avoid sign extension problems with unknown upper bits? */
+	regs->r_gs = tf->tf_gs & 0xffff;
+	regs->r_fs = tf->tf_fs & 0xffff;
+	regs->r_es = tf->tf_es & 0xffff;
+	regs->r_ds = tf->tf_ds & 0xffff;
+	regs->r_eflags = tf->tf_rflags;
 	regs->r_edi = tf->tf_rdi & 0xffffffff;
 	regs->r_esi = tf->tf_rsi & 0xffffffff;
 	regs->r_ebp = tf->tf_rbp & 0xffffffff;
@@ -501,9 +501,9 @@
 	regs->r_ecx = tf->tf_rcx & 0xffffffff;
 	regs->r_eax = tf->tf_rax & 0xffffffff;
 	regs->r_eip = tf->tf_rip & 0xffffffff;
-	regs->r_cs = tf->tf_cs;
+	regs->r_cs = tf->tf_cs & 0xffff;
 	regs->r_esp = tf->tf_rsp & 0xffffffff;
-	regs->r_ss = tf->tf_ss;
+	regs->r_ss = tf->tf_ss & 0xffff;

 	return (0);
 }
@@ -511,22 +511,52 @@
 int
 netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *regs, size_t *sz)
 {
-	struct fpreg regs64;
-	int error;
-	size_t fp_size;
+
+	__CTASSERT(sizeof *regs == sizeof (struct save87));
+	process_read_fpregs_s87(l, (struct save87 *)regs);
+	return 0;
+}
+
+int
+netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
+{
+	struct trapframe *tf = l->l_md.md_regs;

 	/*
-	 * All that stuff makes no sense in i386 code :(
+	 * Check for security violations. Taken from i386/process_machdep.c.
 	 */
+	if (((regs->r_eflags ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 ||
+	    !VALID_USER_CSEL32(regs->r_cs))
+		return EINVAL;

-	fp_size = sizeof regs64;
-	error = process_read_fpregs(l, &regs64, &fp_size);
-	if (error)
-		return error;
-	__CTASSERT(sizeof *regs == sizeof (struct save87));
-	process_xmm_to_s87(&regs64.fxstate, (struct save87 *)regs);
+	tf->tf_rax = regs->r_eax;
+	tf->tf_rcx = regs->r_ecx;
+	tf->tf_rdx = regs->r_edx;
+	tf->tf_rbx = regs->r_ebx;
+	tf->tf_rsp = regs->r_esp;
+	tf->tf_rbp = regs->r_ebp;
+	tf->tf_rsi = regs->r_esi;
+	tf->tf_rdi = regs->r_edi;
+	tf->tf_rip = regs->r_eip;
+	tf->tf_rflags = regs->r_eflags;
+	tf->tf_cs = regs->r_cs;
+	tf->tf_ss = regs->r_ss;
+	tf->tf_ds = regs->r_ds;
+	tf->tf_es = regs->r_es;
+	tf->tf_fs = regs->r_fs;
+	tf->tf_gs = regs->r_gs;

-	return (0);
+	return 0;
+}
+
+int
+netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *regs,
+    size_t sz)
+{
+
+	__CTASSERT(sizeof *regs == sizeof (struct save87));
+	process_write_fpregs_s87(l, (const struct save87 *)regs);
+	return 0;
 }

 int
--- src/sys/arch/amd64/include/ptrace.h.orig	2016-09-27 23:03:04.247552840 +0900
+++ src/sys/arch/amd64/include/ptrace.h	2016-09-27 23:03:44.910371215 +0900
@@ -68,6 +68,9 @@
 #define process_read_regs32	netbsd32_process_read_regs
 #define process_read_fpregs32	netbsd32_process_read_fpregs

+#define process_write_regs32	netbsd32_process_write_regs
+#define process_write_fpregs32	netbsd32_process_write_fpregs
+
 #define process_reg32		struct reg32
 #define process_fpreg32		struct fpreg32
 #endif	/* COMPAT_NETBSD32 */
--- src/sys/arch/amd64/include/netbsd32_machdep.h.orig	2016-09-27 23:07:53.849813992 +0900
+++ src/sys/arch/amd64/include/netbsd32_machdep.h	2016-09-28 00:01:52.104719432 +0900
@@ -138,4 +138,7 @@
 int netbsd32_process_read_regs(struct lwp *, struct reg32 *);
 int netbsd32_process_read_fpregs(struct lwp *, struct fpreg32 *, size_t *);

+int netbsd32_process_write_regs(struct lwp *, const struct reg32 *);
+int netbsd32_process_write_fpregs(struct lwp *, const struct fpreg32 *, size_t);
+
 #endif /* _MACHINE_NETBSD32_H_ */
--- src/sys/arch/sparc64/include/ptrace.h.orig	2016-09-28 07:27:12.604872351 +0900
+++ src/sys/arch/sparc64/include/ptrace.h	2016-09-28 07:27:51.489447290 +0900
@@ -8,9 +8,12 @@
 #ifdef COMPAT_NETBSD32
 #include <compat/netbsd32/netbsd32.h>

-#define process_read_regs32 netbsd32_process_read_regs
+#define process_read_regs32	netbsd32_process_read_regs
 #define process_read_fpregs32	netbsd32_process_read_fpregs

+#define process_write_regs32	netbsd32_process_write_regs
+#define process_write_fpregs32	netbsd32_process_write_fpregs
+
 #define process_reg32		struct reg32
 #define process_fpreg32		struct fpreg32
 #endif
--- src/sys/arch/sparc64/include/netbsd32_machdep.h.orig	2016-09-28 07:28:21.564773071 +0900
+++ src/sys/arch/sparc64/include/netbsd32_machdep.h	2016-09-28 07:28:56.497298977 +0900
@@ -79,4 +79,7 @@
 int netbsd32_process_read_regs(struct lwp *, struct reg32 *);
 int netbsd32_process_read_fpregs(struct lwp *, struct fpreg32 *, size_t *);

+int netbsd32_process_write_regs(struct lwp *, const struct reg32 *);
+int netbsd32_process_write_fpregs(struct lwp *, const struct fpreg32 *, size_t);
+
 #endif /* _MACHINE_NETBSD32_H_ */
--- src/sys/arch/sparc64/sparc64/netbsd32_machdep.c.orig	2016-09-28 07:29:43.583860712 +0900
+++ src/sys/arch/sparc64/sparc64/netbsd32_machdep.c	2016-09-28 11:56:11.368274396 +0900
@@ -624,16 +624,15 @@
 	return (0);
 }

-#if 0
 int
 netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
 {
-	struct trapframe64* tf = p->p_md.md_tf;
+	struct trapframe64* tf = l->l_md.md_tf;
 	int i;

 	tf->tf_pc = regs->r_pc;
 	tf->tf_npc = regs->r_npc;
-	tf->tf_y = regs->r_pc;
+	tf->tf_y = regs->r_y;
 	for (i = 0; i < 8; i++) {
 		tf->tf_global[i] = regs->r_global[i];
 		tf->tf_out[i] = regs->r_out[i];
@@ -643,7 +642,6 @@
 		PSRCC_TO_TSTATE(regs->r_psr);
 	return (0);
 }
-#endif

 int
 netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *regs, size_t *sz)
@@ -661,9 +659,9 @@
 	return 0;
 }

-#if 0
 int
-netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *regs)
+netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *regs,
+    size_t sz)
 {
 	struct fpstate64	*statep;
 	int i;
@@ -678,7 +676,6 @@

 	return 0;
 }
-#endif

 /*
  * 32-bit version of cpu_coredump.
--- src/sys/compat/netbsd32/netbsd32.h.orig	2016-09-27 13:11:26.515967512 +0900
+++ src/sys/compat/netbsd32/netbsd32.h	2016-09-27 14:07:52.164728060 +0900
@@ -282,6 +282,16 @@
 /* from <sys/poll.h> */
 typedef netbsd32_pointer_t netbsd32_pollfdp_t;

+/* from <sys/ptrace.h> */
+typedef netbsd32_pointer_t netbsd32_ptrace_io_descp_t;
+struct netbsd32_ptrace_io_desc {
+	int	piod_op;		/* I/O operation */
+	netbsd32_voidp piod_offs;	/* child offset */
+	netbsd32_voidp piod_addr;	/* parent offset */
+	netbsd32_size_t piod_len;	/* request length (in) /
+					   actual count (out) */
+};
+
 /* from <sys/quotactl.h> */
 typedef netbsd32_pointer_t netbsd32_quotactlargsp_t;
 struct netbsd32_quotactlargs {
--- src/sys/kern/sys_process.c.orig	2016-09-27 11:57:58.429775526 +0900
+++ src/sys/kern/sys_process.c	2016-09-28 07:38:53.092742755 +0900
@@ -120,9 +120,12 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.169 2016/05/25 17:43:58 christos Exp $");

+#ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
 #include "opt_ktrace.h"
 #include "opt_pax.h"
+#include "opt_compat_netbsd32.h"
+#endif

 #include <sys/param.h>
 #include <sys/systm.h>
@@ -142,6 +145,10 @@

 #include <machine/reg.h>

+#ifdef COMPAT_NETBSD32
+#include <compat/netbsd32/netbsd32.h>
+#endif
+
 #ifdef PTRACE

 # ifdef DEBUG
@@ -262,6 +269,10 @@
 	ksiginfo_t ksi;
 	char *path;
 	int len = 0;
+#ifdef COMPAT_NETBSD32
+	struct netbsd32_ptrace_io_desc piod32;
+	int p32 = p->p_flag & PK_32;
+#endif

 	error = 0;
 	req = SCARG(uap, req);
@@ -295,6 +306,18 @@
 		}
 	}

+#ifdef COMPAT_NETBSD32
+	/* The tracer and traced processes must have the same ABI. */
+	if (p32 != (t->p_flag & PK_32)) {
+		/* XXX for GDB to terminate processes of wrong ABI */
+		if (req != PT_KILL) {
+			mutex_exit(proc_lock);
+			mutex_exit(t->p_lock);
+			return EINVAL;
+		}
+	}
+#endif
+
 	/*
 	 * Grab a reference on the process to prevent it from execing or
 	 * exiting.
@@ -534,9 +557,23 @@
 		break;

 	case  PT_IO:
-		error = copyin(SCARG(uap, addr), &piod, sizeof(piod));
-		if (error)
-			break;
+#ifdef COMPAT_NETBSD32
+		if (p32) {
+			error = copyin(SCARG(uap, addr), &piod32,
+			    sizeof(piod32));
+			if (error)
+				break;
+			piod.piod_op = piod32.piod_op;
+			piod.piod_offs = NETBSD32PTR64(piod32.piod_offs);
+			piod.piod_addr = NETBSD32PTR64(piod32.piod_addr);
+			piod.piod_len = (size_t)piod32.piod_len;
+		} else
+#endif
+		{
+			error = copyin(SCARG(uap, addr), &piod, sizeof(piod));
+			if (error)
+				break;
+		}

 		iov.iov_base = piod.piod_addr;
 		iov.iov_len = piod.piod_len;
@@ -563,7 +600,15 @@
 		case PIOD_READ_AUXV:
 			req = PT_READ_D;
 			uio.uio_rw = UIO_READ;
-			tmp = t->p_execsw->es_arglen * sizeof(char *);
+			tmp = t->p_execsw->es_arglen;
+#ifdef COMPAT_NETBSD32
+			if (p32) {
+				tmp *= sizeof(netbsd32_pointer_t);
+			} else
+#endif
+			{
+				tmp *= sizeof(char *);
+			}
 			if (uio.uio_offset > tmp)
 				return EIO;
 			if (uio.uio_resid > tmp - uio.uio_offset)
@@ -586,7 +631,19 @@

 		error = process_domem(l, lt, &uio);
 		piod.piod_len -= uio.uio_resid;
-		(void) copyout(&piod, SCARG(uap, addr), sizeof(piod));
+#ifdef COMPAT_NETBSD32
+		if (p32) {
+			piod32.piod_op = piod.piod_op;
+			NETBSD32PTR32(piod32.piod_offs, piod.piod_offs);
+			NETBSD32PTR32(piod32.piod_addr, piod.piod_addr);
+			piod32.piod_len = (netbsd32_size_t)piod.piod_len;
+			(void) copyout(&piod32, SCARG(uap, addr),
+			    sizeof(piod32));
+		} else
+#endif
+		{
+			(void) copyout(&piod, SCARG(uap, addr), sizeof(piod));
+		}
 		uvmspace_free(vm);
 		break;

@@ -909,11 +966,18 @@
 			if (error)
 				break;
 			iov.iov_base = SCARG(uap, addr);
-			iov.iov_len = sizeof(struct reg);
+#ifdef COMPAT_NETBSD32
+			if (p32) {
+				iov.iov_len = sizeof(process_reg32);
+			} else
+#endif
+			{
+				iov.iov_len = sizeof(struct reg);
+			}
 			uio.uio_iov = &iov;
 			uio.uio_iovcnt = 1;
 			uio.uio_offset = 0;
-			uio.uio_resid = sizeof(struct reg);
+			uio.uio_resid = iov.iov_len;
 			uio.uio_rw = write ? UIO_WRITE : UIO_READ;
 			uio.uio_vmspace = vm;

@@ -952,11 +1016,18 @@
 			if (error)
 				break;
 			iov.iov_base = SCARG(uap, addr);
-			iov.iov_len = sizeof(struct fpreg);
+#ifdef COMPAT_NETBSD32
+			if (p32) {
+				iov.iov_len = sizeof(process_fpreg32);
+			} else
+#endif
+			{
+				iov.iov_len = sizeof(struct fpreg);
+			}
 			uio.uio_iov = &iov;
 			uio.uio_iovcnt = 1;
 			uio.uio_offset = 0;
-			uio.uio_resid = sizeof(struct fpreg);
+			uio.uio_resid = iov.iov_len;
 			uio.uio_rw = write ? UIO_WRITE : UIO_READ;
 			uio.uio_vmspace = vm;

@@ -995,26 +1066,54 @@
 	struct reg r;
 	char *kv;
 	int kl;
-
-	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r))
-		return EINVAL;
-
-	kl = sizeof(r);
-	kv = (char *)&r;
+#ifdef COMPAT_NETBSD32
+	process_reg32 r32;
+	int p32 = l->l_proc->p_flag & PK_32; /* traced */
+#endif
+
+#ifdef COMPAT_NETBSD32
+	if (p32) {
+		if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
+			return EINVAL;
+		kl = sizeof(r32);
+		kv = (char *)&r32;
+	} else
+#endif
+	{
+		if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r))
+			return EINVAL;
+		kl = sizeof(r);
+		kv = (char *)&r;
+	}

 	kv += uio->uio_offset;
 	kl -= uio->uio_offset;
 	if ((size_t)kl > uio->uio_resid)
 		kl = uio->uio_resid;

-	error = process_read_regs(l, &r);
+#ifdef COMPAT_NETBSD32
+	if (p32) {
+		error = process_read_regs32(l, &r32);
+	} else
+#endif
+	{
+		error = process_read_regs(l, &r);
+	}
 	if (error == 0)
 		error = uiomove(kv, kl, uio);
 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
 		if (l->l_stat != LSSTOP)
 			error = EBUSY;
-		else
-			error = process_write_regs(l, &r);
+		else {
+#ifdef COMPAT_NETBSD32
+			if (p32) {
+				error = process_write_regs32(l, &r32);
+			} else
+#endif
+			{
+				error = process_write_regs(l, &r);
+			}
+		}
 	}

 	uio->uio_offset = 0;
@@ -1045,26 +1144,54 @@
 	struct fpreg r;
 	char *kv;
 	size_t kl;
-
-	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r))
-		return EINVAL;
-
-	kl = sizeof(r);
-	kv = (char *)&r;
+#ifdef COMPAT_NETBSD32
+	process_fpreg32 r32;
+	int p32 = l->l_proc->p_flag & PK_32; /* traced */
+#endif
+
+#ifdef COMPAT_NETBSD32
+	if (p32) {
+		if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
+			return EINVAL;
+		kl = sizeof(r32);
+		kv = (char *)&r32;
+	} else
+#endif
+	{
+		if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r))
+			return EINVAL;
+		kl = sizeof(r);
+		kv = (char *)&r;
+	}

 	kv += uio->uio_offset;
 	kl -= uio->uio_offset;
 	if (kl > uio->uio_resid)
 		kl = uio->uio_resid;

-	error = process_read_fpregs(l, &r, &kl);
+#ifdef COMPAT_NETBSD32
+	if (p32) {
+		error = process_read_fpregs32(l, &r32, &kl);
+	} else
+#endif
+	{
+		error = process_read_fpregs(l, &r, &kl);
+	}
 	if (error == 0)
 		error = uiomove(kv, kl, uio);
 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
 		if (l->l_stat != LSSTOP)
 			error = EBUSY;
-		else
-			error = process_write_fpregs(l, &r, kl);
+		else {
+#ifdef COMPAT_NETBSD32
+			if (p32) {
+				error = process_write_fpregs32(l, &r32, kl);
+			} else
+#endif
+			{
+				error = process_write_fpregs(l, &r, kl);
+			}
+		}
 	}
 	uio->uio_offset = 0;
 	return (error);
--- src/sys/sys/ptrace.h.orig	2016-09-27 22:59:47.862486891 +0900
+++ src/sys/sys/ptrace.h	2016-09-28 05:46:26.502778292 +0900
@@ -180,9 +180,21 @@
 int	process_sstep(struct lwp *, int);
 #ifdef PT_SETFPREGS
 int	process_write_fpregs(struct lwp *, const struct fpreg *, size_t);
+#ifndef process_write_fpregs32
+#define process_write_fpregs32	process_write_fpregs
+#endif
+#ifndef process_write_fpregs64
+#define process_write_fpregs64	process_write_fpregs
+#endif
 #endif
 #ifdef PT_SETREGS
 int	process_write_regs(struct lwp *, const struct reg *);
+#ifndef process_write_regs32
+#define process_write_regs32	process_write_regs
+#endif
+#ifndef process_write_regs64
+#define process_write_regs64	process_write_regs
+#endif
 #endif

 #ifdef __HAVE_PROCFS_MACHDEP

>Release-Note:

>Audit-Trail:

Responsible-Changed-From-To: kern-bug-people->skrll
Responsible-Changed-By: skrll@NetBSD.org
Responsible-Changed-When: Wed, 28 Sep 2016 10:28:03 +0000
Responsible-Changed-Why:
take


From: matthew green <mrg@eterna.com.au>
To: gnats-bugs@NetBSD.org
Cc: kern-bug-people@netbsd.org, gnats-admin@netbsd.org,
    netbsd-bugs@netbsd.org
Subject: re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Thu, 29 Sep 2016 03:49:24 +1000

 FWIW, you shouldn't ever have to extract things into /emul/netbsd32
 anymore.  if you find issues that require it, please file PRs about
 them.  eg, binaries should work in any location.

 the problem with your patch is that invades the main kernel with 
 comaptibility code that currently mostly works as a module.  it 
 really would be best to do this in compat/netbsd32 sources.

 thanks.


 .mrg.

From: Rin Okuyama <rokuyama@rk.phys.keio.ac.jp>
To: matthew green <mrg@eterna.com.au>, gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Thu, 29 Sep 2016 22:18:47 +0900

 Thank you very much for your comment.

 On 2016/09/29 2:49, matthew green wrote:
 > FWIW, you shouldn't ever have to extract things into /emul/netbsd32
 > anymore.  if you find issues that require it, please file PRs about
 > them.  eg, binaries should work in any location.

 Yes, I understand. My example was, somewhat, misleading. The location
 of 32-bit version of GDB, etc., is irrelevant to the problem.

 > the problem with your patch is that invades the main kernel with
 > comaptibility code that currently mostly works as a module.  it
 > really would be best to do this in compat/netbsd32 sources.

 I agree with you. But it is difficult, at least for me, to separate
 compatibility code from kern/sys_process.c.

 For sys_ptrace(9), the situation is similar to the case of
 copy_procargs(9) in kern/kern_proc.c, which has also compatibility
 code in it:

    https://nxr.netbsd.org/source/xref/src/sys/kern/kern_proc.c#2086

 The procedure is almost common for native and 32-bit processes, but
 just small parts are different. How do we separate compat code from
 functions like this?

 For process_{,fp}regs(9), the situation is more complicated as they
 are used not only by ptrace(2), but also by procfs.

 I do not, of course, stick to my patch. My hope is just to implement
 COMPAT_NETBSD32 support to ptrace(2); without it, we cannot use GDB
 on mips64 at the moment. I would greatly appreciate it if you kindly
 give me any suggestions.

 Thanks,
 Rin

From: Nick Hudson <skrll@netbsd.org>
To: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org, netbsd-bugs@netbsd.org,
 rokuyama@rk.phys.keio.ac.jp
Cc: 
Subject: Re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Thu, 29 Sep 2016 14:24:23 +0100

 On 09/29/16 14:20, Rin Okuyama wrote:
 > The following reply was made to PR kern/51514; it has been noted by GNATS.
 >
 > From: Rin Okuyama <rokuyama@rk.phys.keio.ac.jp>
 > To: matthew green <mrg@eterna.com.au>, gnats-bugs@NetBSD.org
 > Cc:
 > Subject: Re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
 > Date: Thu, 29 Sep 2016 22:18:47 +0900
 >
 >   Thank you very much for your comment.
 >   
 >   On 2016/09/29 2:49, matthew green wrote:
 >   > FWIW, you shouldn't ever have to extract things into /emul/netbsd32
 >   > anymore.  if you find issues that require it, please file PRs about
 >   > them.  eg, binaries should work in any location.
 >   
 >   Yes, I understand. My example was, somewhat, misleading. The location
 >   of 32-bit version of GDB, etc., is irrelevant to the problem.
 >   
 >   > the problem with your patch is that invades the main kernel with
 >   > comaptibility code that currently mostly works as a module.  it
 >   > really would be best to do this in compat/netbsd32 sources.
 >   
 >   I agree with you. But it is difficult, at least for me, to separate
 >   compatibility code from kern/sys_process.c.
 >   
 >   For sys_ptrace(9), the situation is similar to the case of
 >   copy_procargs(9) in kern/kern_proc.c, which has also compatibility
 >   code in it:
 >   
 >      https://nxr.netbsd.org/source/xref/src/sys/kern/kern_proc.c#2086
 >   
 >   The procedure is almost common for native and 32-bit processes, but
 >   just small parts are different. How do we separate compat code from
 >   functions like this?
 >   
 >   For process_{,fp}regs(9), the situation is more complicated as they
 >   are used not only by ptrace(2), but also by procfs.
 >   
 >   I do not, of course, stick to my patch. My hope is just to implement
 >   COMPAT_NETBSD32 support to ptrace(2); without it, we cannot use GDB
 >   on mips64 at the moment. I would greatly appreciate it if you kindly
 >   give me any suggestions.

 I'm working on this. Hopefully the rabbit hole isn't too deep.

 Nick

From: Rin Okuyama <rokuyama@rk.phys.keio.ac.jp>
To: Nick Hudson <skrll@netbsd.org>, gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Thu, 29 Sep 2016 22:36:59 +0900

 On 2016/09/29 22:24, Nick Hudson wrote:
 > I'm working on this. Hopefully the rabbit hole isn't too deep.

 Thank you always for your kind support :-).

 Rin

From: Nick Hudson <skrll@netbsd.org>
To: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org, netbsd-bugs@netbsd.org,
 rokuyama@rk.phys.keio.ac.jp
Cc: 
Subject: Re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Sun, 16 Oct 2016 09:09:10 +0100

 This is a multi-part message in MIME format.
 --------------050409000904030005020102
 Content-Type: text/plain; charset=utf-8; format=flowed
 Content-Transfer-Encoding: 7bit

 On 09/29/16 14:30, Nick Hudson wrote:
 > The following reply was made to PR kern/51514; it has been noted by GNATS.

 >   >   > the problem with your patch is that invades the main kernel with
 >   >   > comaptibility code that currently mostly works as a module.  it
 >   >   > really would be best to do this in compat/netbsd32 sources.
 >   >
 >   >   I agree with you. But it is difficult, at least for me, to separate
 >   >   compatibility code from kern/sys_process.c.
 >   >
 >   >   For sys_ptrace(9), the situation is similar to the case of
 >   >   copy_procargs(9) in kern/kern_proc.c, which has also compatibility
 >   >   code in it:
 >   >
 >   >https://nxr.netbsd.org/source/xref/src/sys/kern/kern_proc.c#2086
 >   >
 >   >   The procedure is almost common for native and 32-bit processes, but
 >   >   just small parts are different. How do we separate compat code from
 >   >   functions like this?
 >   >
 >   >   For process_{,fp}regs(9), the situation is more complicated as they
 >   >   are used not only by ptrace(2), but also by procfs.
 >   >
 >   >   I do not, of course, stick to my patch. My hope is just to implement
 >   >   COMPAT_NETBSD32 support to ptrace(2); without it, we cannot use GDB
 >   >   on mips64 at the moment. I would greatly appreciate it if you kindly
 >   >   give me any suggestions.
 >   
 >   I'm working on this. Hopefully the rabbit hole isn't too deep.

 Here's what I've got... Some things to nodes are

 - New compat_netbsd32_ptrace modules is created, but a ptrace module isn't
 - Should more be moved into compat32, e.g. PROC_{PTR,REG,FPREG}SZ and
    the netbsd32_process_{read,write}_{,fp}regs?
 -

 --------------050409000904030005020102
 Content-Type: text/x-patch;
  name="ptrace32.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="ptrace32.diff"

 Index: sys/arch/amd64/amd64/netbsd32_machdep.c
 ===================================================================
 RCS file: /cvsroot/src/sys/arch/amd64/amd64/netbsd32_machdep.c,v
 retrieving revision 1.96
 diff -u -p -r1.96 netbsd32_machdep.c
 --- sys/arch/amd64/amd64/netbsd32_machdep.c	2 Sep 2016 07:51:05 -0000	1.96
 +++ sys/arch/amd64/amd64/netbsd32_machdep.c	15 Oct 2016 12:40:13 -0000
 @@ -487,12 +487,12 @@ netbsd32_process_read_regs(struct lwp *l
  {
  	struct trapframe *tf = l->l_md.md_regs;

 -	regs->r_gs = LSEL(LUCODE32_SEL, SEL_UPL);
 -	regs->r_fs = LSEL(LUCODE32_SEL, SEL_UPL);
 -	regs->r_es = LSEL(LUCODE32_SEL, SEL_UPL);
 -	regs->r_ds = LSEL(LUCODE32_SEL, SEL_UPL);
 -	regs->r_eflags = tf->tf_rflags;
  	/* XXX avoid sign extension problems with unknown upper bits? */
 +	regs->r_gs = tf->tf_gs & 0xffff;
 +	regs->r_fs = tf->tf_fs & 0xffff;
 +	regs->r_es = tf->tf_es & 0xffff;
 +	regs->r_ds = tf->tf_ds & 0xffff;
 +	regs->r_eflags = tf->tf_rflags;
  	regs->r_edi = tf->tf_rdi & 0xffffffff;
  	regs->r_esi = tf->tf_rsi & 0xffffffff;
  	regs->r_ebp = tf->tf_rbp & 0xffffffff;
 @@ -501,9 +501,9 @@ netbsd32_process_read_regs(struct lwp *l
  	regs->r_ecx = tf->tf_rcx & 0xffffffff;
  	regs->r_eax = tf->tf_rax & 0xffffffff;
  	regs->r_eip = tf->tf_rip & 0xffffffff;
 -	regs->r_cs = tf->tf_cs;
 +	regs->r_cs = tf->tf_cs & 0xffff;
  	regs->r_esp = tf->tf_rsp & 0xffffffff;
 -	regs->r_ss = tf->tf_ss;
 +	regs->r_ss = tf->tf_ss & 0xffff;

  	return (0);
  }
 @@ -511,22 +511,52 @@ netbsd32_process_read_regs(struct lwp *l
  int
  netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *regs, size_t *sz)
  {
 -	struct fpreg regs64;
 -	int error;
 -	size_t fp_size;
 +
 +	__CTASSERT(sizeof *regs == sizeof (struct save87));
 +	process_read_fpregs_s87(l, (struct save87 *)regs);
 +	return 0;
 +}
 +
 +int
 +netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
 +{
 +	struct trapframe *tf = l->l_md.md_regs;

  	/*
 -	 * All that stuff makes no sense in i386 code :(
 +	 * Check for security violations. Taken from i386/process_machdep.c.
  	 */
 +	if (((regs->r_eflags ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 ||
 +	    !VALID_USER_CSEL32(regs->r_cs))
 +		return EINVAL;

 -	fp_size = sizeof regs64;
 -	error = process_read_fpregs(l, &regs64, &fp_size);
 -	if (error)
 -		return error;
 -	__CTASSERT(sizeof *regs == sizeof (struct save87));
 -	process_xmm_to_s87(&regs64.fxstate, (struct save87 *)regs);
 +	tf->tf_rax = regs->r_eax;
 +	tf->tf_rcx = regs->r_ecx;
 +	tf->tf_rdx = regs->r_edx;
 +	tf->tf_rbx = regs->r_ebx;
 +	tf->tf_rsp = regs->r_esp;
 +	tf->tf_rbp = regs->r_ebp;
 +	tf->tf_rsi = regs->r_esi;
 +	tf->tf_rdi = regs->r_edi;
 +	tf->tf_rip = regs->r_eip;
 +	tf->tf_rflags = regs->r_eflags;
 +	tf->tf_cs = regs->r_cs;
 +	tf->tf_ss = regs->r_ss;
 +	tf->tf_ds = regs->r_ds;
 +	tf->tf_es = regs->r_es;
 +	tf->tf_fs = regs->r_fs;
 +	tf->tf_gs = regs->r_gs;

 -	return (0);
 +	return 0;
 +}
 +
 +int
 +netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *regs,
 +    size_t sz)
 +{
 +
 +	__CTASSERT(sizeof *regs == sizeof (struct save87));
 +	process_write_fpregs_s87(l, (const struct save87 *)regs);
 +	return 0;
  }

  int
 Index: sys/arch/amd64/include/netbsd32_machdep.h
 ===================================================================
 RCS file: /cvsroot/src/sys/arch/amd64/include/netbsd32_machdep.h,v
 retrieving revision 1.19
 diff -u -p -r1.19 netbsd32_machdep.h
 --- sys/arch/amd64/include/netbsd32_machdep.h	7 Feb 2014 22:40:22 -0000	1.19
 +++ sys/arch/amd64/include/netbsd32_machdep.h	15 Oct 2016 12:40:13 -0000
 @@ -138,4 +138,7 @@ struct x86_64_set_mtrr_args32 {
  int netbsd32_process_read_regs(struct lwp *, struct reg32 *);
  int netbsd32_process_read_fpregs(struct lwp *, struct fpreg32 *, size_t *);

 +int netbsd32_process_write_regs(struct lwp *, const struct reg32 *);
 +int netbsd32_process_write_fpregs(struct lwp *, const struct fpreg32 *, size_t);
 +
  #endif /* _MACHINE_NETBSD32_H_ */
 Index: sys/arch/amd64/include/ptrace.h
 ===================================================================
 RCS file: /cvsroot/src/sys/arch/amd64/include/ptrace.h,v
 retrieving revision 1.6
 diff -u -p -r1.6 ptrace.h
 --- sys/arch/amd64/include/ptrace.h	25 Sep 2015 16:05:17 -0000	1.6
 +++ sys/arch/amd64/include/ptrace.h	15 Oct 2016 12:40:13 -0000
 @@ -68,6 +68,9 @@
  #define process_read_regs32	netbsd32_process_read_regs
  #define process_read_fpregs32	netbsd32_process_read_fpregs

 +#define process_write_regs32	netbsd32_process_write_regs
 +#define process_write_fpregs32	netbsd32_process_write_fpregs
 +
  #define process_reg32		struct reg32
  #define process_fpreg32		struct fpreg32
  #endif	/* COMPAT_NETBSD32 */
 Index: sys/arch/sparc64/include/netbsd32_machdep.h
 ===================================================================
 RCS file: /cvsroot/src/sys/arch/sparc64/include/netbsd32_machdep.h,v
 retrieving revision 1.28
 diff -u -p -r1.28 netbsd32_machdep.h
 --- sys/arch/sparc64/include/netbsd32_machdep.h	4 Jan 2014 00:10:03 -0000	1.28
 +++ sys/arch/sparc64/include/netbsd32_machdep.h	15 Oct 2016 12:40:13 -0000
 @@ -79,4 +79,7 @@ int netbsd32_md_ioctl(struct file *, net
  int netbsd32_process_read_regs(struct lwp *, struct reg32 *);
  int netbsd32_process_read_fpregs(struct lwp *, struct fpreg32 *, size_t *);

 +int netbsd32_process_write_regs(struct lwp *, const struct reg32 *);
 +int netbsd32_process_write_fpregs(struct lwp *, const struct fpreg32 *, size_t);
 +
  #endif /* _MACHINE_NETBSD32_H_ */
 Index: sys/arch/sparc64/include/ptrace.h
 ===================================================================
 RCS file: /cvsroot/src/sys/arch/sparc64/include/ptrace.h,v
 retrieving revision 1.4
 diff -u -p -r1.4 ptrace.h
 --- sys/arch/sparc64/include/ptrace.h	28 Sep 2016 11:44:16 -0000	1.4
 +++ sys/arch/sparc64/include/ptrace.h	15 Oct 2016 12:40:13 -0000
 @@ -11,6 +11,9 @@
  #define process_read_regs32	netbsd32_process_read_regs
  #define process_read_fpregs32	netbsd32_process_read_fpregs

 +#define process_write_regs32	netbsd32_process_write_regs
 +#define process_write_fpregs32	netbsd32_process_write_fpregs
 +
  #define process_reg32		struct reg32
  #define process_fpreg32		struct fpreg32
  #endif
 Index: sys/arch/sparc64/sparc64/netbsd32_machdep.c
 ===================================================================
 RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/netbsd32_machdep.c,v
 retrieving revision 1.109
 diff -u -p -r1.109 netbsd32_machdep.c
 --- sys/arch/sparc64/sparc64/netbsd32_machdep.c	26 Nov 2015 13:15:34 -0000	1.109
 +++ sys/arch/sparc64/sparc64/netbsd32_machdep.c	15 Oct 2016 12:40:14 -0000
 @@ -624,16 +624,15 @@ netbsd32_process_read_regs(struct lwp *l
  	return (0);
  }

 -#if 0
  int
  netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
  {
 -	struct trapframe64* tf = p->p_md.md_tf;
 +	struct trapframe64* tf = l->l_md.md_tf;
  	int i;

  	tf->tf_pc = regs->r_pc;
  	tf->tf_npc = regs->r_npc;
 -	tf->tf_y = regs->r_pc;
 +	tf->tf_y = regs->r_y;
  	for (i = 0; i < 8; i++) {
  		tf->tf_global[i] = regs->r_global[i];
  		tf->tf_out[i] = regs->r_out[i];
 @@ -643,7 +642,6 @@ netbsd32_process_write_regs(struct lwp *
  		PSRCC_TO_TSTATE(regs->r_psr);
  	return (0);
  }
 -#endif

  int
  netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *regs, size_t *sz)
 @@ -661,9 +659,9 @@ netbsd32_process_read_fpregs(struct lwp 
  	return 0;
  }

 -#if 0
  int
 -netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *regs)
 +netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *regs,
 +    size_t sz)
  {
  	struct fpstate64	*statep;
  	int i;
 @@ -678,7 +676,6 @@ netbsd32_process_write_fpregs(struct lwp

  	return 0;
  }
 -#endif

  /*
   * 32-bit version of cpu_coredump.
 Index: sys/compat/netbsd32/files.netbsd32
 ===================================================================
 RCS file: /cvsroot/src/sys/compat/netbsd32/files.netbsd32,v
 retrieving revision 1.38
 diff -u -p -r1.38 files.netbsd32
 --- sys/compat/netbsd32/files.netbsd32	3 Dec 2015 11:25:45 -0000	1.38
 +++ sys/compat/netbsd32/files.netbsd32	15 Oct 2016 12:40:14 -0000
 @@ -21,6 +21,7 @@ file	compat/netbsd32/netbsd32_module.c	c
  file	compat/netbsd32/netbsd32_mod.c		compat_netbsd32
  file	compat/netbsd32/netbsd32_mqueue.c	compat_netbsd32 & mqueue
  file	compat/netbsd32/netbsd32_nfssvc.c	compat_netbsd32 & nfsserver
 +file	compat/netbsd32/netbsd32_ptrace.c	compat_netbsd32 & ptrace
  file	compat/netbsd32/netbsd32_select.c	compat_netbsd32
  file	compat/netbsd32/netbsd32_sem.c		compat_netbsd32
  file	compat/netbsd32/netbsd32_signal.c	compat_netbsd32
 Index: sys/compat/netbsd32/netbsd32.h
 ===================================================================
 RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32.h,v
 retrieving revision 1.112
 diff -u -p -r1.112 netbsd32.h
 --- sys/compat/netbsd32/netbsd32.h	23 Sep 2016 14:16:32 -0000	1.112
 +++ sys/compat/netbsd32/netbsd32.h	15 Oct 2016 12:40:17 -0000
 @@ -282,6 +282,16 @@ struct netbsd32_export_args30 {
  /* from <sys/poll.h> */
  typedef netbsd32_pointer_t netbsd32_pollfdp_t;

 +/* from <sys/ptrace.h> */
 +typedef netbsd32_pointer_t netbsd32_ptrace_io_descp_t;
 +struct netbsd32_ptrace_io_desc {
 +	int	piod_op;		/* I/O operation */
 +	netbsd32_voidp piod_offs;	/* child offset */
 +	netbsd32_voidp piod_addr;	/* parent offset */
 +	netbsd32_size_t piod_len;	/* request length (in) /
 +					   actual count (out) */
 +};
 +
  /* from <sys/quotactl.h> */
  typedef netbsd32_pointer_t netbsd32_quotactlargsp_t;
  struct netbsd32_quotactlargs {
 Index: sys/compat/netbsd32/netbsd32_netbsd.c
 ===================================================================
 RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_netbsd.c,v
 retrieving revision 1.204
 diff -u -p -r1.204 netbsd32_netbsd.c
 --- sys/compat/netbsd32/netbsd32_netbsd.c	17 Sep 2016 02:44:38 -0000	1.204
 +++ sys/compat/netbsd32/netbsd32_netbsd.c	15 Oct 2016 12:40:17 -0000
 @@ -406,25 +406,6 @@ netbsd32_setuid(struct lwp *l, const str
  }

  int
 -netbsd32_ptrace(struct lwp *l, const struct netbsd32_ptrace_args *uap, register_t *retval)
 -{
 -	/* {
 -		syscallarg(int) req;
 -		syscallarg(pid_t) pid;
 -		syscallarg(netbsd32_voidp) addr;
 -		syscallarg(int) data;
 -	} */
 -	struct sys_ptrace_args ua;
 -
 -	NETBSD32TO64_UAP(req);
 -	NETBSD32TO64_UAP(pid);
 -	NETBSD32TOP_UAP(addr, void *);
 -	NETBSD32TO64_UAP(data);
 -
 -	return (*sysent[SYS_ptrace].sy_call)(l, &ua, retval);
 -}
 -
 -int
  netbsd32_accept(struct lwp *l, const struct netbsd32_accept_args *uap, register_t *retval)
  {
  	/* {
 Index: sys/compat/netbsd32/netbsd32_ptrace.c
 ===================================================================
 RCS file: sys/compat/netbsd32/netbsd32_ptrace.c
 diff -N sys/compat/netbsd32/netbsd32_ptrace.c
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ sys/compat/netbsd32/netbsd32_ptrace.c	15 Oct 2016 12:40:17 -0000
 @@ -0,0 +1,217 @@
 +/*	$NetBSD$	*/
 +
 +/*
 + * Copyright (c) 2016 The NetBSD Foundation, Inc.
 + * All rights reserved.
 + *
 + * This code is derived from software contributed to The NetBSD Foundation
 + * by Nick Hudson
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 + * POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include <sys/cdefs.h>
 +__KERNEL_RCSID(0, "$NetBSD$");
 +
 +#if defined(_KERNEL_OPT)
 +#include "opt_ptrace.h"
 +#include "opt_compat_netbsd.h"
 +#endif
 +
 +#include <sys/param.h>
 +#include <sys/module.h>
 +#include <sys/ptrace.h>
 +#include <sys/syscallvar.h>
 +
 +#include <compat/netbsd32/netbsd32.h>
 +#include <compat/netbsd32/netbsd32_syscall.h>
 +#include <compat/netbsd32/netbsd32_syscallargs.h>
 +#include <compat/netbsd32/netbsd32_conv.h>
 +
 +extern struct emul emul_netbsd32;
 +
 +
 +/*
 + * PTRACE methods
 + */
 +
 +static int netbsd32_copyinpiod(struct ptrace_io_desc *, const void *);
 +static void netbsd32_copyoutpiod(const struct ptrace_io_desc *, void *);
 +static int netbsd32_doregs(struct lwp *, struct lwp *, struct uio *);
 +static int netbsd32_dofpregs(struct lwp *, struct lwp *, struct uio *);
 +
 +
 +static int
 +netbsd32_copyinpiod(struct ptrace_io_desc *piod, const void *addr)
 +{
 +	struct netbsd32_ptrace_io_desc piod32;
 +
 +	int error = copyin(addr, &piod32, sizeof(piod32));
 +	if (error)
 +		return error;
 +	piod->piod_op = piod32.piod_op;
 +	piod->piod_offs = NETBSD32PTR64(piod32.piod_offs);
 +	piod->piod_addr = NETBSD32PTR64(piod32.piod_addr);
 +	piod->piod_len = (size_t)piod32.piod_len;
 +
 +	return 0;
 +}
 +
 +static void
 +netbsd32_copyoutpiod(const struct ptrace_io_desc *piod, void *addr)
 +{
 +	struct netbsd32_ptrace_io_desc piod32;
 +
 +	piod32.piod_op = piod->piod_op;
 +	NETBSD32PTR32(piod32.piod_offs, piod->piod_offs);
 +	NETBSD32PTR32(piod32.piod_addr, piod->piod_addr);
 +	piod32.piod_len = (netbsd32_size_t)piod->piod_len;
 +	(void) copyout(&piod32, addr, sizeof(piod32));
 +}
 +
 +
 +static int
 +netbsd32_doregs(struct lwp *curl /*tracer*/,
 +    struct lwp *l /*traced*/,
 +    struct uio *uio)
 +{
 +#if defined(PT_GETREGS) || defined(PT_SETREGS)
 +	process_reg32 r32;
 +	int error;
 +	char *kv;
 +	int kl;
 +
 +	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
 +		return EINVAL;
 +
 +	kl = sizeof(r32);
 +	kv = (char *)&r32;
 +
 +	kv += uio->uio_offset;
 +	kl -= uio->uio_offset;
 +	if ((size_t)kl > uio->uio_resid)
 +		kl = uio->uio_resid;
 +	error = process_read_regs32(l, &r32);
 +	if (error == 0)
 +		error = uiomove(kv, kl, uio);
 +	if (error == 0 && uio->uio_rw == UIO_WRITE) {
 +		if (l->l_stat != LSSTOP)
 +			error = EBUSY;
 +		else
 +			error = process_write_regs32(l, &r32);
 +	}
 +
 +	uio->uio_offset = 0;
 +	return error;
 +#else
 +	return EINVAL;
 +#endif
 +}
 +
 +static int
 +netbsd32_dofpregs(struct lwp *curl /*tracer*/,
 +    struct lwp *l /*traced*/,
 +    struct uio *uio)
 +{
 +#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
 +	process_fpreg32 r32;
 +	int error;
 +	char *kv;
 +	size_t kl;
 +
 +	KASSERT(l->l_proc->p_flag & PK_32);
 +	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
 +		return EINVAL;
 +	kl = sizeof(r32);
 +	kv = (char *)&r32;
 +
 +	kv += uio->uio_offset;
 +	kl -= uio->uio_offset;
 +	if (kl > uio->uio_resid)
 +		kl = uio->uio_resid;
 +
 +	error = process_read_fpregs32(l, &r32, &kl);
 +	if (error == 0)
 +		error = uiomove(kv, kl, uio);
 +	if (error == 0 && uio->uio_rw == UIO_WRITE) {
 +		if (l->l_stat != LSSTOP)
 +			error = EBUSY;
 +		else
 +			error = process_write_fpregs32(l, &r32, kl);
 +	}
 +	uio->uio_offset = 0;
 +	return error;
 +#else
 +	return EINVAL;
 +#endif
 +}
 +
 +static struct ptrace_methods netbsd32_ptm = {
 +	.ptm_copyinpiod = netbsd32_copyinpiod,
 +	.ptm_copyoutpiod = netbsd32_copyoutpiod,
 +	.ptm_doregs = netbsd32_doregs,
 +	.ptm_dofpregs = netbsd32_dofpregs
 +};
 +
 +
 +int
 +netbsd32_ptrace(struct lwp *l, const struct netbsd32_ptrace_args *uap,
 +    register_t *retval)
 +{
 +	/* {
 +		syscallarg(int) req;
 +		syscallarg(pid_t) pid;
 +		syscallarg(netbsd32_voidp *) addr;
 +		syscallarg(int) data;
 +	} */
 +
 +	return do_ptrace(&netbsd32_ptm, l, SCARG(uap, req), SCARG(uap, pid),
 +	    SCARG_P32(uap, addr), SCARG(uap, data), retval);
 +}
 +
 +static const struct syscall_package compat_ptrace_syscalls[] = {
 +	{ NETBSD32_SYS_netbsd32_ptrace, 0, (sy_call_t *)netbsd32_ptrace },
 +	{ 0, 0, NULL },
 +};
 +
 +MODULE(MODULE_CLASS_EXEC, compat_netbsd32_ptrace, "compat_netbsd32");
 +
 +static int
 +compat_netbsd32_ptrace_modcmd(modcmd_t cmd, void *arg)
 +{
 +	int error;
 +
 +	switch (cmd) {
 +	case MODULE_CMD_INIT:
 +		error = syscall_establish(&emul_netbsd32,
 +		    compat_ptrace_syscalls);
 +		break;
 +	case MODULE_CMD_FINI:
 +		error = syscall_disestablish(&emul_netbsd32,
 +		    compat_ptrace_syscalls);
 +		break;
 +	default:
 +		error = ENOTTY;
 +		break;
 +	}
 +	return error;
 +}
 Index: sys/compat/netbsd32/netbsd32_syscalls_autoload.c
 ===================================================================
 RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_syscalls_autoload.c,v
 retrieving revision 1.6
 diff -u -p -r1.6 netbsd32_syscalls_autoload.c
 --- sys/compat/netbsd32/netbsd32_syscalls_autoload.c	23 Sep 2016 14:12:25 -0000	1.6
 +++ sys/compat/netbsd32/netbsd32_syscalls_autoload.c	15 Oct 2016 12:40:18 -0000
 @@ -1,4 +1,4 @@
 -/* $NetBSD: netbsd32_syscalls_autoload.c,v 1.6 2016/09/23 14:12:25 skrll Exp $ */
 +/* $NetBSD$ */

  /*
   * System call autoload table.
 @@ -8,10 +8,11 @@
   */

  #include <sys/cdefs.h>
 -__KERNEL_RCSID(0, "$NetBSD: netbsd32_syscalls_autoload.c,v 1.6 2016/09/23 14:12:25 skrll Exp $");
 +__KERNEL_RCSID(0, "$NetBSD$");

  #include <sys/proc.h>
  static struct sc_autoload netbsd32_syscalls_autoload[] = {
 +	    { NETBSD32_SYS_netbsd32_ptrace, "compat_netbsd32_ptrace" },
  	    { NETBSD32_SYS_netbsd32_nfssvc, "compat_netbsd32_nfssrv" },
  	    { NETBSD32_SYS_compat_10_osemsys, "compat_netbsd32_sysvipc" },
  	    { NETBSD32_SYS_compat_10_omsgsys, "compat_netbsd32_sysvipc" },
 Index: sys/compat/netbsd32/netbsd32_sysent.c
 ===================================================================
 RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_sysent.c,v
 retrieving revision 1.123
 diff -u -p -r1.123 netbsd32_sysent.c
 --- sys/compat/netbsd32/netbsd32_sysent.c	23 Sep 2016 14:12:25 -0000	1.123
 +++ sys/compat/netbsd32/netbsd32_sysent.c	15 Oct 2016 12:40:18 -0000
 @@ -1,4 +1,4 @@
 -/* $NetBSD: netbsd32_sysent.c,v 1.123 2016/09/23 14:12:25 skrll Exp $ */
 +/* $NetBSD$ */

  /*
   * System call switch table.
 @@ -8,7 +8,7 @@
   */

  #include <sys/cdefs.h>
 -__KERNEL_RCSID(0, "$NetBSD: netbsd32_sysent.c,v 1.123 2016/09/23 14:12:25 skrll Exp $");
 +__KERNEL_RCSID(0, "$NetBSD$");

  #if defined(_KERNEL_OPT)
  #include "opt_compat_netbsd.h"
 @@ -220,7 +220,7 @@ struct sysent netbsd32_sysent[] = {
  	},		/* 25 = geteuid */
  	{
  		ns(struct netbsd32_ptrace_args),
 -		.sy_call = (sy_call_t *)netbsd32_ptrace
 +		.sy_call = (sy_call_t *)sys_nomodule
  	},		/* 26 = netbsd32_ptrace */
  	{
  		ns(struct netbsd32_recvmsg_args),
 Index: sys/compat/netbsd32/netbsd32_systrace_args.c
 ===================================================================
 RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_systrace_args.c,v
 retrieving revision 1.14
 diff -u -p -r1.14 netbsd32_systrace_args.c
 --- sys/compat/netbsd32/netbsd32_systrace_args.c	23 Sep 2016 14:12:25 -0000	1.14
 +++ sys/compat/netbsd32/netbsd32_systrace_args.c	15 Oct 2016 12:40:21 -0000
 @@ -1,4 +1,4 @@
 -/* $NetBSD: netbsd32_systrace_args.c,v 1.14 2016/09/23 14:12:25 skrll Exp $ */
 +/* $NetBSD$ */

  /*
   * System call argument to DTrace register array converstion.
 Index: sys/compat/netbsd32/syscalls.master
 ===================================================================
 RCS file: /cvsroot/src/sys/compat/netbsd32/syscalls.master,v
 retrieving revision 1.114
 diff -u -p -r1.114 syscalls.master
 --- sys/compat/netbsd32/syscalls.master	23 Sep 2016 14:10:28 -0000	1.114
 +++ sys/compat/netbsd32/syscalls.master	15 Oct 2016 12:40:21 -0000
 @@ -99,7 +99,8 @@
  23	STD		{ int|netbsd32||setuid(uid_t uid); }
  24	NOARGS 		{ uid_t|sys||getuid(void); }
  25	NOARGS		{ uid_t|sys||geteuid(void); }
 -26	STD		{ int|netbsd32||ptrace(int req, pid_t pid, \
 +26	STD MODULAR compat_netbsd32_ptrace \
 +			{ int|netbsd32||ptrace(int req, pid_t pid, \
  			    netbsd32_voidp addr, int data); }
  27	STD		{ netbsd32_ssize_t|netbsd32||recvmsg(int s, \
  			    netbsd32_msghdrp_t msg, int flags); }
 Index: sys/kern/sys_process.c
 ===================================================================
 RCS file: /cvsroot/src/sys/kern/sys_process.c,v
 retrieving revision 1.173
 diff -u -p -r1.173 sys_process.c
 --- sys/kern/sys_process.c	15 Oct 2016 09:09:55 -0000	1.173
 +++ sys/kern/sys_process.c	15 Oct 2016 12:40:21 -0000
 @@ -120,9 +120,11 @@
  #include <sys/cdefs.h>
  __KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.173 2016/10/15 09:09:55 skrll Exp $");

 +#ifdef _KERNEL_OPT
  #include "opt_ptrace.h"
  #include "opt_ktrace.h"
  #include "opt_pax.h"
 +#endif

  #include <sys/param.h>
  #include <sys/systm.h>
 @@ -231,6 +233,26 @@ ptrace_init(void)
  	    ptrace_listener_cb, NULL);
  }

 +static int
 +ptrace_copyinpiod(struct ptrace_io_desc *piod, const void *addr)
 +{
 +	return copyin(addr, piod, sizeof(*piod));
 +}
 +
 +static void
 +ptrace_copyoutpiod(const struct ptrace_io_desc *piod, void *addr)
 +{
 +	(void) copyout(piod, addr, sizeof(*piod));
 +}
 +
 +
 +static struct ptrace_methods native_ptm = {
 +	.ptm_copyinpiod = ptrace_copyinpiod,
 +	.ptm_copyoutpiod = ptrace_copyoutpiod,
 +	.ptm_doregs = process_doregs,
 +	.ptm_dofpregs = process_dofpregs,
 +};
 +
  /*
   * Process debugging system call.
   */
 @@ -243,6 +265,15 @@ sys_ptrace(struct lwp *l, const struct s
  		syscallarg(void *) addr;
  		syscallarg(int) data;
  	} */
 +
 +	return do_ptrace(&native_ptm, l, SCARG(uap, req), SCARG(uap, pid),
 +	    SCARG(uap, addr), SCARG(uap, data), retval);
 +}
 +
 +int
 +do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid,
 +    void *addr, int data, register_t *retval)
 +{
  	struct proc *p = l->l_proc;
  	struct lwp *lt;
  #ifdef PT_STEP
 @@ -256,15 +287,13 @@ sys_ptrace(struct lwp *l, const struct s
  	struct ptrace_state ps;
  	struct ptrace_lwpinfo pl;
  	struct vmspace *vm;
 -	int error, write, tmp, req, pheld;
 +	int error, write, tmp, pheld;
  	int signo = 0;
  	int resume_all;
  	ksiginfo_t ksi;
  	char *path;
  	int len = 0;
 -
  	error = 0;
 -	req = SCARG(uap, req);

  	/*
  	 * If attaching or detaching, we need to get a write hold on the
 @@ -278,7 +307,7 @@ sys_ptrace(struct lwp *l, const struct s
  		mutex_enter(t->p_lock);
  	} else {
  		/* Find the process we're supposed to be operating on. */
 -		t = proc_find(SCARG(uap, pid));
 +		t = proc_find(pid);
  		if (t == NULL) {
  			mutex_exit(proc_lock);
  			return ESRCH;
 @@ -507,13 +536,13 @@ sys_ptrace(struct lwp *l, const struct s
  		/*
  		 * Can't write to a RAS
  		 */
 -		if (ras_lookup(t, SCARG(uap, addr)) != (void *)-1) {
 +		if (ras_lookup(t, addr) != (void *)-1) {
  			error = EACCES;
  			break;
  		}
  #endif
  		write = 1;
 -		tmp = SCARG(uap, data);
 +		tmp = data;
  		/* FALLTHROUGH */

  	case  PT_READ_I:		/* XXX no separate I and D spaces */
 @@ -523,7 +552,7 @@ sys_ptrace(struct lwp *l, const struct s
  		iov.iov_len = sizeof(tmp);
  		uio.uio_iov = &iov;
  		uio.uio_iovcnt = 1;
 -		uio.uio_offset = (off_t)(unsigned long)SCARG(uap, addr);
 +		uio.uio_offset = (off_t)(unsigned long)addr;
  		uio.uio_resid = sizeof(tmp);
  		uio.uio_rw = write ? UIO_WRITE : UIO_READ;
  		UIO_SETUP_SYSSPACE(&uio);
 @@ -534,7 +563,7 @@ sys_ptrace(struct lwp *l, const struct s
  		break;

  	case  PT_IO:
 -		error = copyin(SCARG(uap, addr), &piod, sizeof(piod));
 +		error = ptm->ptm_copyinpiod(&piod, addr);
  		if (error)
  			break;

 @@ -555,7 +584,7 @@ sys_ptrace(struct lwp *l, const struct s
  			/*
  			 * Can't write to a RAS
  			 */
 -			if (ras_lookup(t, SCARG(uap, addr)) != (void *)-1) {
 +			if (ras_lookup(t, addr) != (void *)-1) {
  				return EACCES;
  			}
  			uio.uio_rw = UIO_WRITE;
 @@ -586,14 +615,15 @@ sys_ptrace(struct lwp *l, const struct s

  		error = process_domem(l, lt, &uio);
  		piod.piod_len -= uio.uio_resid;
 -		(void) copyout(&piod, SCARG(uap, addr), sizeof(piod));
 +		(void) ptm->ptm_copyoutpiod(&piod, addr);
 +
  		uvmspace_free(vm);
  		break;

  	case  PT_DUMPCORE:
 -		if ((path = SCARG(uap, addr)) != NULL) {
 +		if ((path = addr) != NULL) {
  			char *dst;
 -			len = SCARG(uap, data);
 +			len = data;

  			if (len < 0 || len >= MAXPATHLEN) {
  				error = EINVAL;
 @@ -648,7 +678,7 @@ sys_ptrace(struct lwp *l, const struct s
  		 * For operations other than PT_STEP, data > 0 means
  		 * data is the signo to deliver to the process.
  		 */
 -		tmp = SCARG(uap, data);
 +		tmp = data;
  		if (tmp >= 0) {
  #ifdef PT_STEP
  			if (req == PT_STEP)
 @@ -697,8 +727,8 @@ sys_ptrace(struct lwp *l, const struct s
  		}

  		/* If the address parameter is not (int *)1, set the pc. */
 -		if ((int *)SCARG(uap, addr) != (int *)1) {
 -			error = process_set_pc(lt, SCARG(uap, addr));
 +		if ((int *)addr != (int *)1) {
 +			error = process_set_pc(lt, addr);
  			if (error != 0)
  				break;
  		}
 @@ -797,26 +827,26 @@ sys_ptrace(struct lwp *l, const struct s
  		goto sendsig;

  	case  PT_GET_EVENT_MASK:
 -		if (SCARG(uap, data) != sizeof(pe)) {
 +		if (data != sizeof(pe)) {
  			DPRINTF(("ptrace(%d): %d != %zu\n", req,
 -			    SCARG(uap, data), sizeof(pe)));
 +			    data, sizeof(pe)));
  			error = EINVAL;
  			break;
  		}
  		memset(&pe, 0, sizeof(pe));
  		pe.pe_set_event = ISSET(t->p_slflag, PSL_TRACEFORK) ?
  		    PTRACE_FORK : 0;
 -		error = copyout(&pe, SCARG(uap, addr), sizeof(pe));
 +		error = copyout(&pe, addr, sizeof(pe));
  		break;

  	case  PT_SET_EVENT_MASK:
 -		if (SCARG(uap, data) != sizeof(pe)) {
 -			DPRINTF(("ptrace(%d): %d != %zu\n", req,
 -			    SCARG(uap, data), sizeof(pe)));
 +		if (data != sizeof(pe)) {
 +			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
 +			    sizeof(pe)));
  			error = EINVAL;
  			break;
  		}
 -		if ((error = copyin(SCARG(uap, addr), &pe, sizeof(pe))) != 0)
 +		if ((error = copyin(addr, &pe, sizeof(pe))) != 0)
  			return error;
  		if (pe.pe_set_event & PTRACE_FORK)
  			SET(t->p_slflag, PSL_TRACEFORK);
 @@ -825,9 +855,9 @@ sys_ptrace(struct lwp *l, const struct s
  		break;

  	case  PT_GET_PROCESS_STATE:
 -		if (SCARG(uap, data) != sizeof(ps)) {
 -			DPRINTF(("ptrace(%d): %d != %zu\n", req,
 -			    SCARG(uap, data), sizeof(ps)));
 +		if (data != sizeof(ps)) {
 +			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
 +			    sizeof(ps)));
  			error = EINVAL;
  			break;
  		}
 @@ -836,17 +866,17 @@ sys_ptrace(struct lwp *l, const struct s
  			ps.pe_report_event = PTRACE_FORK;
  			ps.pe_other_pid = t->p_fpid;
  		}
 -		error = copyout(&ps, SCARG(uap, addr), sizeof(ps));
 +		error = copyout(&ps, addr, sizeof(ps));
  		break;

  	case PT_LWPINFO:
 -		if (SCARG(uap, data) != sizeof(pl)) {
 -			DPRINTF(("ptrace(%d): %d != %zu\n", req,
 -			    SCARG(uap, data), sizeof(pl)));
 +		if (data != sizeof(pl)) {
 +			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
 +			    sizeof(pl)));
  			error = EINVAL;
  			break;
  		}
 -		error = copyin(SCARG(uap, addr), &pl, sizeof(pl));
 +		error = copyin(addr, &pl, sizeof(pl));
  		if (error)
  			break;
  		tmp = pl.pl_lwpid;
 @@ -875,7 +905,7 @@ sys_ptrace(struct lwp *l, const struct s
  		}
  		mutex_exit(t->p_lock);

 -		error = copyout(&pl, SCARG(uap, addr), sizeof(pl));
 +		error = copyout(&pl, addr, sizeof(pl));
  		break;

  #ifdef PT_SETREGS
 @@ -887,7 +917,7 @@ sys_ptrace(struct lwp *l, const struct s
  		/* write = 0 done above. */
  #endif
  #if defined(PT_SETREGS) || defined(PT_GETREGS)
 -		tmp = SCARG(uap, data);
 +		tmp = data;
  		if (tmp != 0 && t->p_nlwps > 1) {
  			lwp_delref(lt);
  			mutex_enter(t->p_lock);
 @@ -903,19 +933,19 @@ sys_ptrace(struct lwp *l, const struct s
  		if (!process_validregs(lt))
  			error = EINVAL;
  		else {
 -			error = proc_vmspace_getref(l->l_proc, &vm);
 +			error = proc_vmspace_getref(p, &vm);
  			if (error)
  				break;
 -			iov.iov_base = SCARG(uap, addr);
 -			iov.iov_len = sizeof(struct reg);
 +			iov.iov_base = addr;
 +			iov.iov_len = PROC_REGSZ(p);
  			uio.uio_iov = &iov;
  			uio.uio_iovcnt = 1;
  			uio.uio_offset = 0;
 -			uio.uio_resid = sizeof(struct reg);
 +			uio.uio_resid = iov.iov_len;
  			uio.uio_rw = write ? UIO_WRITE : UIO_READ;
  			uio.uio_vmspace = vm;

 -			error = process_doregs(l, lt, &uio);
 +			error = ptm->ptm_doregs(l, lt, &uio);
  			uvmspace_free(vm);
  		}
  		break;
 @@ -930,7 +960,7 @@ sys_ptrace(struct lwp *l, const struct s
  		/* write = 0 done above. */
  #endif
  #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
 -		tmp = SCARG(uap, data);
 +		tmp = data;
  		if (tmp != 0 && t->p_nlwps > 1) {
  			lwp_delref(lt);
  			mutex_enter(t->p_lock);
 @@ -946,19 +976,19 @@ sys_ptrace(struct lwp *l, const struct s
  		if (!process_validfpregs(lt))
  			error = EINVAL;
  		else {
 -			error = proc_vmspace_getref(l->l_proc, &vm);
 +			error = proc_vmspace_getref(p, &vm);
  			if (error)
  				break;
 -			iov.iov_base = SCARG(uap, addr);
 -			iov.iov_len = sizeof(struct fpreg);
 +			iov.iov_base = addr;
 +			iov.iov_len = PROC_FPREGSZ(p);
  			uio.uio_iov = &iov;
  			uio.uio_iovcnt = 1;
  			uio.uio_offset = 0;
 -			uio.uio_resid = sizeof(struct fpreg);
 +			uio.uio_resid = iov.iov_len;
  			uio.uio_rw = write ? UIO_WRITE : UIO_READ;
  			uio.uio_vmspace = vm;

 -			error = process_dofpregs(l, lt, &uio);
 +			error = ptm->ptm_dofpregs(l, lt, &uio);
  			uvmspace_free(vm);
  		}
  		break;
 @@ -966,8 +996,7 @@ sys_ptrace(struct lwp *l, const struct s

  #ifdef __HAVE_PTRACE_MACHDEP
  	PTRACE_MACHDEP_REQUEST_CASES
 -		error = ptrace_machdep_dorequest(l, lt,
 -		    req, SCARG(uap, addr), SCARG(uap, data));
 +		error = ptrace_machdep_dorequest(l, lt, req, addr, data);
  		break;
  #endif
  	}
 Index: sys/modules/Makefile
 ===================================================================
 RCS file: /cvsroot/src/sys/modules/Makefile,v
 retrieving revision 1.180
 diff -u -p -r1.180 Makefile
 --- sys/modules/Makefile	15 Oct 2016 12:38:03 -0000	1.180
 +++ sys/modules/Makefile	15 Oct 2016 12:40:21 -0000
 @@ -236,6 +236,7 @@ SUBDIR+=	wmimsi
  SUBDIR+=	compat_netbsd32
  SUBDIR+=	compat_netbsd32_mqueue
  SUBDIR+=	compat_netbsd32_nfssrv
 +SUBDIR+=	compat_netbsd32_ptrace
  SUBDIR+=	compat_netbsd32_sysvipc
  .endif

 @@ -244,6 +245,7 @@ SUBDIR+=	compat_linux32
  SUBDIR+=	compat_netbsd32
  SUBDIR+=	compat_netbsd32_mqueue
  SUBDIR+=	compat_netbsd32_nfssrv
 +SUBDIR+=	compat_netbsd32_ptrace
  SUBDIR+=	compat_netbsd32_sysvipc
  .endif

 Index: sys/sys/proc.h
 ===================================================================
 RCS file: /cvsroot/src/sys/sys/proc.h,v
 retrieving revision 1.334
 diff -u -p -r1.334 proc.h
 --- sys/sys/proc.h	29 Sep 2016 20:40:53 -0000	1.334
 +++ sys/sys/proc.h	15 Oct 2016 12:40:22 -0000
 @@ -557,6 +557,10 @@ _proclist_skipmarker(struct proc *p0)
  }

  #define PROC_PTRSZ(p) (((p)->p_flag & PK_32) ? sizeof(int) : sizeof(void *))
 +#define PROC_REGSZ(p) (((p)->p_flag & PK_32) ? \
 +    sizeof(process_reg32) : sizeof(struct reg))
 +#define PROC_FPREGSZ(p) (((p)->p_flag & PK_32) ? \
 +    sizeof(process_fpreg32) : sizeof(struct fpreg))

  /*
   * PROCLIST_FOREACH: iterate on the given proclist, skipping PK_MARKER ones.
 Index: sys/sys/ptrace.h
 ===================================================================
 RCS file: /cvsroot/src/sys/sys/ptrace.h,v
 retrieving revision 1.46
 diff -u -p -r1.46 ptrace.h
 --- sys/sys/ptrace.h	2 Jul 2015 03:47:54 -0000	1.46
 +++ sys/sys/ptrace.h	15 Oct 2016 12:40:22 -0000
 @@ -139,6 +139,13 @@ struct fpreg;
  #endif
  #endif

 +struct ptrace_methods {
 +	int (*ptm_copyinpiod)(struct ptrace_io_desc *, const void *);
 +	void (*ptm_copyoutpiod)(const struct ptrace_io_desc *, void *);
 +	int (*ptm_doregs)(struct lwp *, struct lwp *, struct uio *);
 +	int (*ptm_dofpregs)(struct lwp *, struct lwp *, struct uio *);
 +};
 +
  void	ptrace_init(void);

  int	process_doregs(struct lwp *, struct lwp *, struct uio *);
 @@ -153,6 +160,10 @@ void	process_stoptrace(void);

  void	proc_reparent(struct proc *, struct proc *);

 +
 +int	do_ptrace(struct ptrace_methods *, struct lwp *, int, pid_t, void *,
 +	    int, register_t *);
 +
  /*
   * 64bit architectures that support 32bit emulation (amd64 and sparc64)
   * will #define process_read_regs32 to netbsd32_process_read_regs (etc).
 @@ -180,9 +191,21 @@ int	process_set_pc(struct lwp *, void *)
  int	process_sstep(struct lwp *, int);
  #ifdef PT_SETFPREGS
  int	process_write_fpregs(struct lwp *, const struct fpreg *, size_t);
 +#ifndef process_write_fpregs32
 +#define process_write_fpregs32	process_write_fpregs
 +#endif
 +#ifndef process_write_fpregs64
 +#define process_write_fpregs64	process_write_fpregs
 +#endif
  #endif
  #ifdef PT_SETREGS
  int	process_write_regs(struct lwp *, const struct reg *);
 +#ifndef process_write_regs32
 +#define process_write_regs32	process_write_regs
 +#endif
 +#ifndef process_write_regs64
 +#define process_write_regs64	process_write_regs
 +#endif
  #endif

  #ifdef __HAVE_PROCFS_MACHDEP



 --------------050409000904030005020102
 Content-Type: text/plain; charset=UTF-8;
  name="Makefile"
 Content-Transfer-Encoding: base64
 Content-Disposition: attachment;
  filename="Makefile"

 IwkkTmV0QlNEJAoKLmluY2x1ZGUgIi4uL01ha2VmaWxlLmluYyIKLmluY2x1ZGUgIi4uL01h
 a2VmaWxlLmFzc3ltIgoKS01PRD0JY29tcGF0X25ldGJzZDMyX3B0cmFjZQoKQ1BQRkxBR1Mr
 PQktRENPTVBBVF9ORVRCU0QzMgpDUFBGTEFHUys9CS1EUFRSQUNFCkNQUEZMQUdTKz0JLURQ
 VF9TRVRSRUdTIC1EUFRfR0VUUkVHUwoKLlBBVEg6CSR7U30vY29tcGF0L25ldGJzZDMyClNS
 Q1MrPQluZXRic2QzMl9wdHJhY2UuYwoKLmluY2x1ZGUgPGJzZC5rbW9kdWxlLm1rPgoK
 --------------050409000904030005020102--

From: matthew green <mrg@eterna.com.au>
To: Nick Hudson <skrll@netbsd.org>
Cc: gnats-bugs@NetBSD.org, gnats-admin@netbsd.org,
    netbsd-bugs@netbsd.org, rokuyama@rk.phys.keio.ac.jp
Subject: re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Mon, 17 Oct 2016 05:33:39 +1100

 >  	/* XXX avoid sign extension problems with unknown upper bits? */
 > +	regs->r_gs = tf->tf_gs & 0xffff;
 > +	regs->r_fs = tf->tf_fs & 0xffff;
 > +	regs->r_es = tf->tf_es & 0xffff;
 > +	regs->r_ds = tf->tf_ds & 0xffff;
 > +	regs->r_eflags = tf->tf_rflags;
 > @@ -501,9 +501,9 @@ netbsd32_process_read_regs(struct lwp *l
 > -	regs->r_cs = tf->tf_cs;
 > +	regs->r_cs = tf->tf_cs & 0xffff;
 >  	regs->r_esp = tf->tf_rsp & 0xffffffff;
 > -	regs->r_ss = tf->tf_ss;
 > +	regs->r_ss = tf->tf_ss & 0xffff;

 i wonder if there should be ASSERT()s that they're not set.  there
 really should never be anything set here.  x86-heads?

 > -	tf->tf_y = regs->r_pc;
 > +	tf->tf_y = regs->r_y;

 well spotted.

 rest LGTM and what i was envisioning.  thanks!


 .mrg.

From: David Holland <dholland-bugs@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Sun, 16 Oct 2016 19:14:21 +0000

 On Sun, Oct 16, 2016 at 06:35:00PM +0000, matthew green wrote:
  >  >  	/* XXX avoid sign extension problems with unknown upper bits? */
  >  > +	regs->r_gs = tf->tf_gs & 0xffff;
  >  > +	regs->r_fs = tf->tf_fs & 0xffff;
  >  > +	regs->r_es = tf->tf_es & 0xffff;
  >  > +	regs->r_ds = tf->tf_ds & 0xffff;
  >  > +	regs->r_eflags = tf->tf_rflags;
  >  > @@ -501,9 +501,9 @@ netbsd32_process_read_regs(struct lwp *l
  >  > -	regs->r_cs = tf->tf_cs;
  >  > +	regs->r_cs = tf->tf_cs & 0xffff;
  >  >  	regs->r_esp = tf->tf_rsp & 0xffffffff;
  >  > -	regs->r_ss = tf->tf_ss;
  >  > +	regs->r_ss = tf->tf_ss & 0xffff;
  >  
  >  i wonder if there should be ASSERT()s that they're not set.  there
  >  really should never be anything set here.  x86-heads?

 The way the amd64 trapframe structure is built (via cpp abuse) causes
 the segment register fields to be uint64_t. Therefore as long as they
 have i386 segment selector values in them, which are 16 bits wide,
 everything should be ok... unless they're sign-extended 16-bit values.
 I have no idea if they manifest that way in hardware (I would think it
 unlikely) or if there's a way for them to get sign-extended in the
 trapframe before they get here (also seems unlikely) but masking them
 is cheap.

 It shouldn't be possible for a 32-bit process to get a 64-bit segment
 register value and it might be a good idea to assert that. Maybe
 something like

    assert(regs->r_gs == tf->tf_gs ||
           regs->r_gs == ((uint64_t)(int64_t)(int16_t)tf->tf_gs))

 The problem is that i386 segment selectors that are negative 16-bit
 values only happen if you have that many segments ( >= 4096, i think,
 but I can't remember for sure) and that is going to be rare even with
 large programs in Wine. So it's probably a good idea to be paranoid
 about it as getting it wrong will lead to lurking problems later.

 -- 
 David A. Holland
 dholland@netbsd.org

From: Rin Okuyama <rokuyama@rk.phys.keio.ac.jp>
To: Nick Hudson <skrll@netbsd.org>, gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel
Date: Tue, 18 Oct 2016 08:37:55 +0900

 On 2016/10/16 17:09, Nick Hudson wrote:
 > Here's what I've got... Some things to nodes are
 >
 > - New compat_netbsd32_ptrace modules is created, but a ptrace module isn't

 Thank you so much for your efforts to modularize 32-bit version of
 ptrace. It's also been a good education for me. I've confirmed that
 32-bit version of GDB works well with your patch on amd64, sparc64,
 andevbmips64-eb.

 > - Should more be moved into compat32, e.g. PROC_{PTR,REG,FPREG}SZ and
 >   the netbsd32_process_{read,write}_{,fp}regs?

 Yes, it should be for the latter. Otherwise, on non-COMPAT_NETBSD32
 kernel, process_{read,write}_{,fp}regs32 are replaced by their 64-bit
 counterparts:

    https://nxr.netbsd.org/source/xref/src/sys/sys/ptrace.h#156

 And therefore compat_netbsd32_ptrace module may not work properly.

 On the other hand, it seems to be harmless for me to have
 PROC_{PTR,REG,FPREG}SZ in the main kernel. Or would it be better to
 protect them by _LP64 like this?

 #ifdef _LP64
 #define PROC_PTRSZ(p) (((p)->p_flag & PK_32) ? sizeof(int) : sizeof(void *))
 #define PROC_REGSZ(p) (((p)->p_flag & PK_32) ? \
      sizeof(process_reg32) : sizeof(struct reg))
 #define PROC_FPREGSZ(p) (((p)->p_flag & PK_32) ? \
      sizeof(process_fpreg32) : sizeof(struct fpreg))
 #else
 #define PROC_PTRSZ(p) sizeof(void *)
 #define PROC_REGSZ(p) sizeof(struct reg)
 #define PROC_FPREGSZ(p) sizeof(struct fpreg)
 #endif

 For registers of x86, I have no ideas. Sorry but I do not have a
 thorough knowledge of x86 architecture...

 Thanks,
 Rin

From: "Nick Hudson" <skrll@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/51514 CVS commit: src
Date: Wed, 19 Oct 2016 09:44:01 +0000

 Module Name:	src
 Committed By:	skrll
 Date:		Wed Oct 19 09:44:01 UTC 2016

 Modified Files:
 	src/distrib/sets/lists/modules: ad.arm ad.mips md.amd64
 	src/sys/arch/amd64/amd64: netbsd32_machdep.c
 	src/sys/arch/amd64/include: netbsd32_machdep.h ptrace.h
 	src/sys/arch/sparc64/include: netbsd32_machdep.h ptrace.h
 	src/sys/arch/sparc64/sparc64: netbsd32_machdep.c
 	src/sys/compat/netbsd32: files.netbsd32 netbsd32.h netbsd32_fs.c
 	    netbsd32_netbsd.c syscalls.master
 	src/sys/kern: sys_process.c
 	src/sys/modules: Makefile
 	src/sys/sys: proc.h ptrace.h
 Added Files:
 	src/sys/compat/netbsd32: netbsd32_ptrace.c
 	src/sys/modules/compat_netbsd32_ptrace: Makefile

 Log Message:
 PR kern/51514: ptrace(2) fails for 32-bit process on 64-bit kernel

 Updated from the original patch in the PR by me.


 To generate a diff of this commit:
 cvs rdiff -u -r1.8 -r1.9 src/distrib/sets/lists/modules/ad.arm \
     src/distrib/sets/lists/modules/ad.mips
 cvs rdiff -u -r1.69 -r1.70 src/distrib/sets/lists/modules/md.amd64
 cvs rdiff -u -r1.96 -r1.97 src/sys/arch/amd64/amd64/netbsd32_machdep.c
 cvs rdiff -u -r1.19 -r1.20 src/sys/arch/amd64/include/netbsd32_machdep.h
 cvs rdiff -u -r1.6 -r1.7 src/sys/arch/amd64/include/ptrace.h
 cvs rdiff -u -r1.28 -r1.29 src/sys/arch/sparc64/include/netbsd32_machdep.h
 cvs rdiff -u -r1.4 -r1.5 src/sys/arch/sparc64/include/ptrace.h
 cvs rdiff -u -r1.109 -r1.110 src/sys/arch/sparc64/sparc64/netbsd32_machdep.c
 cvs rdiff -u -r1.38 -r1.39 src/sys/compat/netbsd32/files.netbsd32
 cvs rdiff -u -r1.112 -r1.113 src/sys/compat/netbsd32/netbsd32.h
 cvs rdiff -u -r1.75 -r1.76 src/sys/compat/netbsd32/netbsd32_fs.c
 cvs rdiff -u -r1.204 -r1.205 src/sys/compat/netbsd32/netbsd32_netbsd.c
 cvs rdiff -u -r0 -r1.1 src/sys/compat/netbsd32/netbsd32_ptrace.c
 cvs rdiff -u -r1.114 -r1.115 src/sys/compat/netbsd32/syscalls.master
 cvs rdiff -u -r1.173 -r1.174 src/sys/kern/sys_process.c
 cvs rdiff -u -r1.180 -r1.181 src/sys/modules/Makefile
 cvs rdiff -u -r0 -r1.1 src/sys/modules/compat_netbsd32_ptrace/Makefile
 cvs rdiff -u -r1.334 -r1.335 src/sys/sys/proc.h
 cvs rdiff -u -r1.46 -r1.47 src/sys/sys/ptrace.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->closed
State-Changed-By: skrll@NetBSD.org
State-Changed-When: Sat, 05 Nov 2016 08:14:59 +0000
State-Changed-Why:
Change committed


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.