Module Name: src
Committed By: pgoyette
Date: Wed Nov 2 00:12:00 UTC 2016
Modified Files:
src/sys/arch/i386/conf: INSTALL_FLOPPY
src/sys/arch/i386/i386: process_machdep.c
src/sys/arch/sh3/include: userret.h
src/sys/arch/sh3/sh3: exception_vector.S process_machdep.c
sh3_machdep.c
src/sys/compat/netbsd32: netbsd32_ptrace.c
src/sys/conf: files std
src/sys/kern: files.kern init_main.c kern_stub.c sys_process.c
syscalls.master
src/sys/miscfs/procfs: files.procfs
src/sys/modules: Makefile
src/sys/sys: ptrace.h
Added Files:
src/sys/kern: sys_ptrace.c sys_ptrace_common.c
src/sys/modules/ptrace: Makefile
src/sys/modules/ptrace_common: Makefile
Log Message:
* Split sys/kern/sys_process.c into three parts:
1 - ptrace(2) syscall for native emulation
2 - common ptrace(2) syscall code (shared with compat_netbsd32)
3 - support routines that are shared with PROCFS and/or KTRACE
* Add module glue for #1 and #2. Both modules will be built-in to the
kernel if "options PTRACE" is included in the config file (this is
the default, defined in sys/conf/std).
* Mark the ptrace(2) syscall as modular in syscalls.master (generated
files will be committed shortly).
* Conditionalize all remaining portions of PTRACE code on a new kernel
option PTRACE_HOOKS.
XXX Instead of PROCFS depending on 'options PTRACE', we should probably
just add a procfs attribute to the sys/kern/sys_process.c file's
entry in files.kern, and add PROCFS to the "#if defineds" for
process_domem(). It's really confusing to have two different ways
of requiring this file.
To generate a diff of this commit:
cvs rdiff -u -r1.29 -r1.30 src/sys/arch/i386/conf/INSTALL_FLOPPY
cvs rdiff -u -r1.85 -r1.86 src/sys/arch/i386/i386/process_machdep.c
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/sh3/include/userret.h
cvs rdiff -u -r1.49 -r1.50 src/sys/arch/sh3/sh3/exception_vector.S
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/sh3/sh3/process_machdep.c
cvs rdiff -u -r1.103 -r1.104 src/sys/arch/sh3/sh3/sh3_machdep.c
cvs rdiff -u -r1.1 -r1.2 src/sys/compat/netbsd32/netbsd32_ptrace.c
cvs rdiff -u -r1.1165 -r1.1166 src/sys/conf/files
cvs rdiff -u -r1.21 -r1.22 src/sys/conf/std
cvs rdiff -u -r1.12 -r1.13 src/sys/kern/files.kern
cvs rdiff -u -r1.483 -r1.484 src/sys/kern/init_main.c
cvs rdiff -u -r1.42 -r1.43 src/sys/kern/kern_stub.c
cvs rdiff -u -r1.174 -r1.175 src/sys/kern/sys_process.c
cvs rdiff -u -r0 -r1.1 src/sys/kern/sys_ptrace.c \
src/sys/kern/sys_ptrace_common.c
cvs rdiff -u -r1.285 -r1.286 src/sys/kern/syscalls.master
cvs rdiff -u -r1.9 -r1.10 src/sys/miscfs/procfs/files.procfs
cvs rdiff -u -r1.181 -r1.182 src/sys/modules/Makefile
cvs rdiff -u -r0 -r1.1 src/sys/modules/ptrace/Makefile
cvs rdiff -u -r0 -r1.1 src/sys/modules/ptrace_common/Makefile
cvs rdiff -u -r1.47 -r1.48 src/sys/sys/ptrace.h
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/i386/conf/INSTALL_FLOPPY
diff -u src/sys/arch/i386/conf/INSTALL_FLOPPY:1.29 src/sys/arch/i386/conf/INSTALL_FLOPPY:1.30
--- src/sys/arch/i386/conf/INSTALL_FLOPPY:1.29 Sat Sep 26 11:16:12 2015
+++ src/sys/arch/i386/conf/INSTALL_FLOPPY Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-# $NetBSD: INSTALL_FLOPPY,v 1.29 2015/09/26 11:16:12 maxv Exp $
+# $NetBSD: INSTALL_FLOPPY,v 1.30 2016/11/02 00:11:59 pgoyette Exp $
#
# INSTALL - Installation kernel.
#
@@ -64,6 +64,7 @@ options PIPE_SOCKETPAIR # smaller, but
no options EXEC_AOUT
no options RFC2292 # Previous version of Adv. Sockets API for IPv6
+no options PTRACE_HOOKS
no options PTRACE # Include ptrace(2)
# Diagnostic/debugging support options
Index: src/sys/arch/i386/i386/process_machdep.c
diff -u src/sys/arch/i386/i386/process_machdep.c:1.85 src/sys/arch/i386/i386/process_machdep.c:1.86
--- src/sys/arch/i386/i386/process_machdep.c:1.85 Wed Feb 19 21:23:01 2014
+++ src/sys/arch/i386/i386/process_machdep.c Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.85 2014/02/19 21:23:01 dsl Exp $ */
+/* $NetBSD: process_machdep.c,v 1.86 2016/11/02 00:11:59 pgoyette Exp $ */
/*-
* Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -52,7 +52,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.85 2014/02/19 21:23:01 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.86 2016/11/02 00:11:59 pgoyette Exp $");
#include "opt_vm86.h"
#include "opt_ptrace.h"
@@ -129,7 +129,7 @@ process_read_fpregs(struct lwp *l, struc
return 0;
}
-#ifdef PTRACE
+#ifdef PTRACE_HOOKS
int
process_write_regs(struct lwp *l, const struct reg *regs)
{
@@ -336,4 +336,4 @@ process_machdep_validxmmregs(struct proc
return (i386_use_fxsave);
}
#endif /* __HAVE_PTRACE_MACHDEP */
-#endif /* PTRACE */
+#endif /* PTRACE_HOOKS */
Index: src/sys/arch/sh3/include/userret.h
diff -u src/sys/arch/sh3/include/userret.h:1.13 src/sys/arch/sh3/include/userret.h:1.14
--- src/sys/arch/sh3/include/userret.h:1.13 Sun Jul 8 20:14:11 2012
+++ src/sys/arch/sh3/include/userret.h Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: userret.h,v 1.13 2012/07/08 20:14:11 dsl Exp $ */
+/* $NetBSD: userret.h,v 1.14 2016/11/02 00:11:59 pgoyette Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@@ -54,7 +54,7 @@ userret(struct lwp *l)
/* Invoke MI userret code */
mi_userret(l);
-#ifdef PTRACE
+#ifdef PTRACE_HOOKS
/* Check if lwp is being PT_STEP'ed */
if (l->l_md.md_flags & MDL_SSTEP) {
struct trapframe *tf = l->l_md.md_regs;
@@ -75,7 +75,7 @@ userret(struct lwp *l)
}
#endif
}
-#endif /* PTRACE */
+#endif /* PTRACE_HOOKS */
}
#endif /* !_SH3_USERRET_H_ */
Index: src/sys/arch/sh3/sh3/exception_vector.S
diff -u src/sys/arch/sh3/sh3/exception_vector.S:1.49 src/sys/arch/sh3/sh3/exception_vector.S:1.50
--- src/sys/arch/sh3/sh3/exception_vector.S:1.49 Fri Feb 4 04:14:25 2011
+++ src/sys/arch/sh3/sh3/exception_vector.S Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: exception_vector.S,v 1.49 2011/02/04 04:14:25 uwe Exp $ */
+/* $NetBSD: exception_vector.S,v 1.50 2016/11/02 00:11:59 pgoyette Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
#define _ALIGN_TEXT .align 5
#include <sh3/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: exception_vector.S,v 1.49 2011/02/04 04:14:25 uwe Exp $")
+__KERNEL_RCSID(0, "$NetBSD: exception_vector.S,v 1.50 2016/11/02 00:11:59 pgoyette Exp $")
/*
@@ -98,7 +98,7 @@ NENTRY(sh_vector_generic)
/* general_exception(curlwp, tf, TEA); */
1: mov r4, r8
-#if defined(PTRACE) || defined(DDB)
+#if defined(PTRACE_HOOKS) || defined(DDB)
mov #0, r2
MOV (BBRA, r1)
mov.l r2, @(TF_UBC, r14) /* clear tf->tf_ubc */
@@ -115,7 +115,7 @@ NENTRY(sh_vector_generic)
jsr @r0
mov r14, r5
-#if defined(PTRACE) || defined(DDB)
+#if defined(PTRACE_HOOKS) || defined(DDB)
mov.l @(TF_UBC, r14), r2
tst r2, r2 ! single-step == 0?
bt .Lg_return_from_exception
Index: src/sys/arch/sh3/sh3/process_machdep.c
diff -u src/sys/arch/sh3/sh3/process_machdep.c:1.20 src/sys/arch/sh3/sh3/process_machdep.c:1.21
--- src/sys/arch/sh3/sh3/process_machdep.c:1.20 Sun Jul 8 20:14:12 2012
+++ src/sys/arch/sh3/sh3/process_machdep.c Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.20 2012/07/08 20:14:12 dsl Exp $ */
+/* $NetBSD: process_machdep.c,v 1.21 2016/11/02 00:11:59 pgoyette Exp $ */
/*
* Copyright (c) 1993 The Regents of the University of California.
@@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.20 2012/07/08 20:14:12 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.21 2016/11/02 00:11:59 pgoyette Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -101,7 +101,7 @@ static int process_machdep_write_regs40(
#endif /* COMPAT_40 */
-#if defined(PTRACE) || defined(COREDUMP)
+#if defined(PTRACE_HOOKS) || defined(COREDUMP)
static inline struct trapframe *
process_frame(struct lwp *l)
@@ -141,10 +141,10 @@ process_read_regs(struct lwp *l, struct
return (0);
}
-#endif /* PTRACE || COREDUMP */
+#endif /* PTRACE_HOOKS || COREDUMP */
-#ifdef PTRACE
+#ifdef PTRACE_HOOKS
int
process_write_regs(struct lwp *l, const struct reg *regs)
@@ -360,4 +360,4 @@ process_set_pc(struct lwp *l, void *addr
return (0);
}
-#endif /* PTRACE */
+#endif /* PTRACE_HOOKS */
Index: src/sys/arch/sh3/sh3/sh3_machdep.c
diff -u src/sys/arch/sh3/sh3/sh3_machdep.c:1.103 src/sys/arch/sh3/sh3/sh3_machdep.c:1.104
--- src/sys/arch/sh3/sh3/sh3_machdep.c:1.103 Sun Nov 22 18:44:25 2015
+++ src/sys/arch/sh3/sh3/sh3_machdep.c Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: sh3_machdep.c,v 1.103 2015/11/22 18:44:25 tsutsui Exp $ */
+/* $NetBSD: sh3_machdep.c,v 1.104 2016/11/02 00:11:59 pgoyette Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2002 The NetBSD Foundation, Inc.
@@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.103 2015/11/22 18:44:25 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.104 2016/11/02 00:11:59 pgoyette Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@@ -194,7 +194,7 @@ sh_cpu_init(int arch, int product)
uvm_setpagesize();
/* setup UBC channel A for single-stepping */
-#if defined(PTRACE) || defined(DDB)
+#if defined(PTRACE_HOOKS) || defined(DDB)
_reg_write_2(SH_(BBRA), 0); /* disable channel A */
_reg_write_2(SH_(BBRB), 0); /* disable channel B */
Index: src/sys/compat/netbsd32/netbsd32_ptrace.c
diff -u src/sys/compat/netbsd32/netbsd32_ptrace.c:1.1 src/sys/compat/netbsd32/netbsd32_ptrace.c:1.2
--- src/sys/compat/netbsd32/netbsd32_ptrace.c:1.1 Wed Oct 19 09:44:01 2016
+++ src/sys/compat/netbsd32/netbsd32_ptrace.c Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_ptrace.c,v 1.1 2016/10/19 09:44:01 skrll Exp $ */
+/* $NetBSD: netbsd32_ptrace.c,v 1.2 2016/11/02 00:11:59 pgoyette Exp $ */
/*
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.1 2016/10/19 09:44:01 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.2 2016/11/02 00:11:59 pgoyette Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ptrace.h"
@@ -193,7 +193,9 @@ static const struct syscall_package comp
{ 0, 0, NULL },
};
-MODULE(MODULE_CLASS_EXEC, compat_netbsd32_ptrace, "compat_netbsd32");
+#define DEPS "compat_netbsd32,ptrace_common"
+
+MODULE(MODULE_CLASS_EXEC, compat_netbsd32_ptrace, DEPS);
static int
compat_netbsd32_ptrace_modcmd(modcmd_t cmd, void *arg)
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1165 src/sys/conf/files:1.1166
--- src/sys/conf/files:1.1165 Tue Nov 1 22:54:33 2016
+++ src/sys/conf/files Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1165 2016/11/01 22:54:33 pgoyette Exp $
+# $NetBSD: files,v 1.1166 2016/11/02 00:11:59 pgoyette Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20150846
@@ -21,7 +21,7 @@ defparam opt_param.h MAXUSERS
defflag INSECURE
defflag KTRACE
defflag MBUFTRACE
-defflag PTRACE
+defflag opt_ptrace.h PTRACE PTRACE_HOOKS
defflag COREDUMP
defflag opt_modular.h MODULAR
defflag opt_modular.h MODULAR_DEFAULT_AUTOLOAD
Index: src/sys/conf/std
diff -u src/sys/conf/std:1.21 src/sys/conf/std:1.22
--- src/sys/conf/std:1.21 Sat Nov 14 07:31:13 2015
+++ src/sys/conf/std Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-# $NetBSD: std,v 1.21 2015/11/14 07:31:13 pgoyette Exp $
+# $NetBSD: std,v 1.22 2016/11/02 00:11:59 pgoyette Exp $
#
# standard MI 'options'
#
@@ -27,7 +27,8 @@ options VMSWAP # Swap device/file suppo
options BUFQ_FCFS # First-come First-serve strategy
options BUFQ_DISKSORT # Traditional min seek sort strategy
options RFC2292 # Previous version of Adv. Sockets API for IPv6
-options PTRACE # Include ptrace(2)
+options PTRACE # Include ptrace(2) syscall
+options PTRACE_HOOKS # Include ptrace hooks
options COREDUMP # allow processes to coredump.
options AIO # POSIX asynchronous I/O
options MQUEUE # POSIX message queues
Index: src/sys/kern/files.kern
diff -u src/sys/kern/files.kern:1.12 src/sys/kern/files.kern:1.13
--- src/sys/kern/files.kern:1.12 Fri Sep 16 03:10:45 2016
+++ src/sys/kern/files.kern Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-# $NetBSD: files.kern,v 1.12 2016/09/16 03:10:45 pgoyette Exp $
+# $NetBSD: files.kern,v 1.13 2016/11/02 00:11:59 pgoyette Exp $
#
# kernel sources
@@ -144,7 +144,9 @@ file kern/sys_mqueue.c mqueue
file kern/sys_lwp.c kern
file kern/sys_pipe.c !pipe_socketpair
file kern/sys_pmc.c kern
-file kern/sys_process.c ptrace | ktrace
+file kern/sys_process.c ptrace_hooks | ktrace
+file kern/sys_ptrace.c ptrace
+file kern/sys_ptrace_common.c ptrace
file kern/sys_pset.c kern
file kern/sys_select.c kern
file kern/sys_sig.c kern
Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.483 src/sys/kern/init_main.c:1.484
--- src/sys/kern/init_main.c:1.483 Sat Sep 17 12:09:22 2016
+++ src/sys/kern/init_main.c Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: init_main.c,v 1.483 2016/09/17 12:09:22 maxv Exp $ */
+/* $NetBSD: init_main.c,v 1.484 2016/11/02 00:11:59 pgoyette Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.483 2016/09/17 12:09:22 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.484 2016/11/02 00:11:59 pgoyette Exp $");
#include "opt_ddb.h"
#include "opt_inet.h"
@@ -190,9 +190,6 @@ extern void *_binary_splash_image_end;
#endif
#include <sys/kauth.h>
#include <net80211/ieee80211_netbsd.h>
-#ifdef PTRACE
-#include <sys/ptrace.h>
-#endif /* PTRACE */
#include <sys/cprng.h>
#include <sys/syscall.h>
@@ -563,11 +560,6 @@ main(void)
ktrinit();
#endif
-#ifdef PTRACE
- /* Initialize ptrace. */
- ptrace_init();
-#endif /* PTRACE */
-
machdep_init();
procinit_sysctl();
Index: src/sys/kern/kern_stub.c
diff -u src/sys/kern/kern_stub.c:1.42 src/sys/kern/kern_stub.c:1.43
--- src/sys/kern/kern_stub.c:1.42 Fri Aug 28 07:18:39 2015
+++ src/sys/kern/kern_stub.c Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_stub.c,v 1.42 2015/08/28 07:18:39 knakahara Exp $ */
+/* $NetBSD: kern_stub.c,v 1.43 2016/11/02 00:11:59 pgoyette Exp $ */
/*-
* Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
@@ -62,10 +62,9 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.42 2015/08/28 07:18:39 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.43 2016/11/02 00:11:59 pgoyette Exp $");
#ifdef _KERNEL_OPT
-#include "opt_ptrace.h"
#include "opt_ktrace.h"
#endif
@@ -87,14 +86,6 @@ bool default_bus_space_handle_is_equal(b
bus_space_handle_t);
/*
- * Nonexistent system call-- signal process (may want to handle it). Flag
- * error in case process won't see signal immediately (blocked or ignored).
- */
-#ifndef PTRACE
-__strong_alias(sys_ptrace,sys_nosys);
-#endif /* PTRACE */
-
-/*
* ktrace stubs. ktruser() goes to enosys as we want to fail the syscall,
* but not kill the process: utrace() is a debugging feature.
*/
Index: src/sys/kern/sys_process.c
diff -u src/sys/kern/sys_process.c:1.174 src/sys/kern/sys_process.c:1.175
--- src/sys/kern/sys_process.c:1.174 Wed Oct 19 09:44:01 2016
+++ src/sys/kern/sys_process.c Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_process.c,v 1.174 2016/10/19 09:44:01 skrll Exp $ */
+/* $NetBSD: sys_process.c,v 1.175 2016/11/02 00:11:59 pgoyette Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.174 2016/10/19 09:44:01 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.175 2016/11/02 00:11:59 pgoyette Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -144,975 +144,7 @@ __KERNEL_RCSID(0, "$NetBSD: sys_process.
#include <machine/reg.h>
-#ifdef PTRACE
-
-# ifdef DEBUG
-# define DPRINTF(a) uprintf a
-# else
-# define DPRINTF(a)
-# endif
-
-static kauth_listener_t ptrace_listener;
-#ifdef PTRACE
-static int process_auxv_offset(struct proc *, struct uio *);
-#endif
-
-static int
-ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
- void *arg0, void *arg1, void *arg2, void *arg3)
-{
- struct proc *p;
- int result;
-
- result = KAUTH_RESULT_DEFER;
- p = arg0;
-
- if (action != KAUTH_PROCESS_PTRACE)
- return result;
-
- switch ((u_long)arg1) {
- case PT_TRACE_ME:
- case PT_ATTACH:
- case PT_WRITE_I:
- case PT_WRITE_D:
- case PT_READ_I:
- case PT_READ_D:
- case PT_IO:
-#ifdef PT_GETREGS
- case PT_GETREGS:
-#endif
-#ifdef PT_SETREGS
- case PT_SETREGS:
-#endif
-#ifdef PT_GETFPREGS
- case PT_GETFPREGS:
-#endif
-#ifdef PT_SETFPREGS
- case PT_SETFPREGS:
-#endif
- case PT_SET_EVENT_MASK:
- case PT_GET_EVENT_MASK:
- case PT_GET_PROCESS_STATE:
-#ifdef __HAVE_PTRACE_MACHDEP
- PTRACE_MACHDEP_REQUEST_CASES
-#endif
- if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) ||
- ISSET(p->p_flag, PK_SUGID)) {
- break;
- }
-
- result = KAUTH_RESULT_ALLOW;
-
- break;
-
-#ifdef PT_STEP
- case PT_STEP:
-#endif
- case PT_CONTINUE:
- case PT_KILL:
- case PT_DETACH:
- case PT_LWPINFO:
- case PT_SYSCALL:
- case PT_SYSCALLEMU:
- case PT_DUMPCORE:
- result = KAUTH_RESULT_ALLOW;
- break;
-
- default:
- break;
- }
-
- return result;
-}
-
-void
-ptrace_init(void)
-{
-
- ptrace_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
- 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.
- */
-int
-sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval)
-{
- /* {
- syscallarg(int) req;
- syscallarg(pid_t) pid;
- 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
- struct lwp *lt2;
-#endif
- struct proc *t; /* target process */
- struct uio uio;
- struct iovec iov;
- struct ptrace_io_desc piod;
- struct ptrace_event pe;
- struct ptrace_state ps;
- struct ptrace_lwpinfo pl;
- struct vmspace *vm;
- int error, write, tmp, pheld;
- int signo = 0;
- int resume_all;
- ksiginfo_t ksi;
- char *path;
- int len = 0;
- error = 0;
-
- /*
- * If attaching or detaching, we need to get a write hold on the
- * proclist lock so that we can re-parent the target process.
- */
- mutex_enter(proc_lock);
-
- /* "A foolish consistency..." XXX */
- if (req == PT_TRACE_ME) {
- t = p;
- mutex_enter(t->p_lock);
- } else {
- /* Find the process we're supposed to be operating on. */
- t = proc_find(pid);
- if (t == NULL) {
- mutex_exit(proc_lock);
- return ESRCH;
- }
-
- /* XXX-elad */
- mutex_enter(t->p_lock);
- error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
- t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
- if (error) {
- mutex_exit(proc_lock);
- mutex_exit(t->p_lock);
- return ESRCH;
- }
- }
-
- /*
- * Grab a reference on the process to prevent it from execing or
- * exiting.
- */
- if (!rw_tryenter(&t->p_reflock, RW_READER)) {
- mutex_exit(proc_lock);
- mutex_exit(t->p_lock);
- return EBUSY;
- }
-
- /* Make sure we can operate on it. */
- switch (req) {
- case PT_TRACE_ME:
- /* Saying that you're being traced is always legal. */
- break;
-
- case PT_ATTACH:
- /*
- * You can't attach to a process if:
- * (1) it's the process that's doing the attaching,
- */
- if (t->p_pid == p->p_pid) {
- error = EINVAL;
- break;
- }
-
- /*
- * (2) it's a system process
- */
- if (t->p_flag & PK_SYSTEM) {
- error = EPERM;
- break;
- }
-
- /*
- * (3) it's already being traced, or
- */
- if (ISSET(t->p_slflag, PSL_TRACED)) {
- error = EBUSY;
- break;
- }
-
- /*
- * (4) the tracer is chrooted, and its root directory is
- * not at or above the root directory of the tracee
- */
- mutex_exit(t->p_lock); /* XXXSMP */
- tmp = proc_isunder(t, l);
- mutex_enter(t->p_lock); /* XXXSMP */
- if (!tmp) {
- error = EPERM;
- break;
- }
- break;
-
- case PT_READ_I:
- case PT_READ_D:
- case PT_WRITE_I:
- case PT_WRITE_D:
- case PT_IO:
-#ifdef PT_GETREGS
- case PT_GETREGS:
-#endif
-#ifdef PT_SETREGS
- case PT_SETREGS:
-#endif
-#ifdef PT_GETFPREGS
- case PT_GETFPREGS:
-#endif
-#ifdef PT_SETFPREGS
- case PT_SETFPREGS:
-#endif
-#ifdef __HAVE_PTRACE_MACHDEP
- PTRACE_MACHDEP_REQUEST_CASES
-#endif
- /*
- * You can't read/write the memory or registers of a process
- * if the tracer is chrooted, and its root directory is not at
- * or above the root directory of the tracee.
- */
- mutex_exit(t->p_lock); /* XXXSMP */
- tmp = proc_isunder(t, l);
- mutex_enter(t->p_lock); /* XXXSMP */
- if (!tmp) {
- error = EPERM;
- break;
- }
- /*FALLTHROUGH*/
-
- case PT_CONTINUE:
- case PT_KILL:
- case PT_DETACH:
- case PT_LWPINFO:
- case PT_SYSCALL:
- case PT_SYSCALLEMU:
- case PT_DUMPCORE:
-#ifdef PT_STEP
- case PT_STEP:
-#endif
- case PT_SET_EVENT_MASK:
- case PT_GET_EVENT_MASK:
- case PT_GET_PROCESS_STATE:
- /*
- * You can't do what you want to the process if:
- * (1) It's not being traced at all,
- */
- if (!ISSET(t->p_slflag, PSL_TRACED)) {
- error = EPERM;
- break;
- }
-
- /*
- * (2) it's being traced by procfs (which has
- * different signal delivery semantics),
- */
- if (ISSET(t->p_slflag, PSL_FSTRACE)) {
- DPRINTF(("file system traced\n"));
- error = EBUSY;
- break;
- }
-
- /*
- * (3) it's not being traced by _you_, or
- */
- if (t->p_pptr != p) {
- DPRINTF(("parent %d != %d\n", t->p_pptr->p_pid,
- p->p_pid));
- error = EBUSY;
- break;
- }
-
- /*
- * (4) it's not currently stopped.
- */
- if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) {
- DPRINTF(("stat %d flag %d\n", t->p_stat,
- !t->p_waited));
- error = EBUSY;
- break;
- }
- break;
-
- default: /* It was not a legal request. */
- error = EINVAL;
- break;
- }
-
- if (error == 0) {
- error = kauth_authorize_process(l->l_cred,
- KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req),
- NULL, NULL);
- }
- if (error == 0) {
- lt = lwp_find_first(t);
- if (lt == NULL)
- error = ESRCH;
- }
-
- if (error != 0) {
- mutex_exit(proc_lock);
- mutex_exit(t->p_lock);
- rw_exit(&t->p_reflock);
- return error;
- }
-
- /* Do single-step fixup if needed. */
- FIX_SSTEP(t);
- KASSERT(lt != NULL);
- lwp_addref(lt);
-
- /*
- * Which locks do we need held? XXX Ugly.
- */
- switch (req) {
-#ifdef PT_STEP
- case PT_STEP:
-#endif
- case PT_CONTINUE:
- case PT_DETACH:
- case PT_KILL:
- case PT_SYSCALL:
- case PT_SYSCALLEMU:
- case PT_ATTACH:
- case PT_TRACE_ME:
- pheld = 1;
- break;
- default:
- mutex_exit(proc_lock);
- mutex_exit(t->p_lock);
- pheld = 0;
- break;
- }
-
- /* Now do the operation. */
- write = 0;
- *retval = 0;
- tmp = 0;
- resume_all = 1;
-
- switch (req) {
- case PT_TRACE_ME:
- /* Just set the trace flag. */
- SET(t->p_slflag, PSL_TRACED);
- t->p_opptr = t->p_pptr;
- break;
-
- case PT_WRITE_I: /* XXX no separate I and D spaces */
- case PT_WRITE_D:
-#if defined(__HAVE_RAS)
- /*
- * Can't write to a RAS
- */
- if (ras_lookup(t, addr) != (void *)-1) {
- error = EACCES;
- break;
- }
-#endif
- write = 1;
- tmp = data;
- /* FALLTHROUGH */
-
- case PT_READ_I: /* XXX no separate I and D spaces */
- case PT_READ_D:
- /* write = 0 done above. */
- iov.iov_base = (void *)&tmp;
- iov.iov_len = sizeof(tmp);
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- 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);
-
- error = process_domem(l, lt, &uio);
- if (!write)
- *retval = tmp;
- break;
-
- case PT_IO:
- error = ptm->ptm_copyinpiod(&piod, addr);
- if (error)
- break;
-
- iov.iov_base = piod.piod_addr;
- iov.iov_len = piod.piod_len;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_offset = (off_t)(unsigned long)piod.piod_offs;
- uio.uio_resid = piod.piod_len;
-
- switch (piod.piod_op) {
- case PIOD_READ_D:
- case PIOD_READ_I:
- uio.uio_rw = UIO_READ;
- break;
- case PIOD_WRITE_D:
- case PIOD_WRITE_I:
- /*
- * Can't write to a RAS
- */
- if (ras_lookup(t, addr) != (void *)-1) {
- return EACCES;
- }
- uio.uio_rw = UIO_WRITE;
- break;
- case PIOD_READ_AUXV:
- req = PT_READ_D;
- uio.uio_rw = UIO_READ;
- tmp = t->p_execsw->es_arglen * PROC_PTRSZ(t);
- if (uio.uio_offset > tmp)
- return EIO;
- if (uio.uio_resid > tmp - uio.uio_offset)
- uio.uio_resid = tmp - uio.uio_offset;
- piod.piod_len = iov.iov_len = uio.uio_resid;
- error = process_auxv_offset(t, &uio);
- if (error)
- return error;
- break;
- default:
- error = EINVAL;
- break;
- }
- if (error)
- break;
- error = proc_vmspace_getref(l->l_proc, &vm);
- if (error)
- break;
- uio.uio_vmspace = vm;
-
- error = process_domem(l, lt, &uio);
- piod.piod_len -= uio.uio_resid;
- (void) ptm->ptm_copyoutpiod(&piod, addr);
-
- uvmspace_free(vm);
- break;
-
- case PT_DUMPCORE:
- if ((path = addr) != NULL) {
- char *dst;
- len = data;
-
- if (len < 0 || len >= MAXPATHLEN) {
- error = EINVAL;
- break;
- }
- dst = kmem_alloc(len + 1, KM_SLEEP);
- if ((error = copyin(path, dst, len)) != 0) {
- kmem_free(dst, len + 1);
- break;
- }
- path = dst;
- path[len] = '\0';
- }
- error = (*coredump_vec)(lt, path);
- if (path)
- kmem_free(path, len + 1);
- break;
-
-#ifdef PT_STEP
- case PT_STEP:
- /*
- * From the 4.4BSD PRM:
- * "Execution continues as in request PT_CONTINUE; however
- * as soon as possible after execution of at least one
- * instruction, execution stops again. [ ... ]"
- */
-#endif
- case PT_CONTINUE:
- case PT_SYSCALL:
- case PT_DETACH:
- if (req == PT_SYSCALL) {
- if (!ISSET(t->p_slflag, PSL_SYSCALL)) {
- SET(t->p_slflag, PSL_SYSCALL);
-#ifdef __HAVE_SYSCALL_INTERN
- (*t->p_emul->e_syscall_intern)(t);
-#endif
- }
- } else {
- if (ISSET(t->p_slflag, PSL_SYSCALL)) {
- CLR(t->p_slflag, PSL_SYSCALL);
-#ifdef __HAVE_SYSCALL_INTERN
- (*t->p_emul->e_syscall_intern)(t);
-#endif
- }
- }
- t->p_trace_enabled = trace_is_enabled(t);
-
- /*
- * Pick up the LWPID, if supplied. There are two cases:
- * data < 0 : step or continue single thread, lwp = -data
- * data > 0 in PT_STEP : step this thread, continue others
- * For operations other than PT_STEP, data > 0 means
- * data is the signo to deliver to the process.
- */
- tmp = data;
- if (tmp >= 0) {
-#ifdef PT_STEP
- if (req == PT_STEP)
- signo = 0;
- else
-#endif
- {
- signo = tmp;
- tmp = 0; /* don't search for LWP */
- }
- } else
- tmp = -tmp;
-
- if (tmp > 0) {
- if (req == PT_DETACH) {
- error = EINVAL;
- break;
- }
- lwp_delref2 (lt);
- lt = lwp_find(t, tmp);
- if (lt == NULL) {
- error = ESRCH;
- break;
- }
- lwp_addref(lt);
- resume_all = 0;
- signo = 0;
- }
-
- /*
- * From the 4.4BSD PRM:
- * "The data argument is taken as a signal number and the
- * child's execution continues at location addr as if it
- * incurred that signal. Normally the signal number will
- * be either 0 to indicate that the signal that caused the
- * stop should be ignored, or that value fetched out of
- * the process's image indicating which signal caused
- * the stop. If addr is (int *)1 then execution continues
- * from where it stopped."
- */
-
- /* Check that the data is a valid signal number or zero. */
- if (signo < 0 || signo >= NSIG) {
- error = EINVAL;
- break;
- }
-
- /* If the address parameter is not (int *)1, set the pc. */
- if ((int *)addr != (int *)1) {
- error = process_set_pc(lt, addr);
- if (error != 0)
- break;
- }
-#ifdef PT_STEP
- /*
- * Arrange for a single-step, if that's requested and possible.
- * More precisely, set the single step status as requested for
- * the requested thread, and clear it for other threads.
- */
- LIST_FOREACH(lt2, &t->p_lwps, l_sibling) {
- if (lt != lt2) {
- lwp_lock(lt2);
- process_sstep(lt2, 0);
- lwp_unlock(lt2);
- }
- }
- error = process_sstep(lt, req == PT_STEP);
- if (error)
- break;
-#endif
- if (req == PT_DETACH) {
- CLR(t->p_slflag, PSL_TRACED|PSL_FSTRACE|PSL_SYSCALL);
-
- /* give process back to original parent or init */
- if (t->p_opptr != t->p_pptr) {
- struct proc *pp = t->p_opptr;
- proc_reparent(t, pp ? pp : initproc);
- }
-
- /* not being traced any more */
- t->p_opptr = NULL;
- }
- sendsig:
- t->p_fpid = 0;
- /* Finally, deliver the requested signal (or none). */
- if (t->p_stat == SSTOP) {
- /*
- * Unstop the process. If it needs to take a
- * signal, make all efforts to ensure that at
- * an LWP runs to see it.
- */
- t->p_xsig = signo;
- if (resume_all)
- proc_unstop(t);
- else
- lwp_unstop(lt);
- } else if (signo != 0) {
- KSI_INIT_EMPTY(&ksi);
- ksi.ksi_signo = signo;
- kpsignal2(t, &ksi);
- }
- break;
-
- case PT_SYSCALLEMU:
- if (!ISSET(t->p_slflag, PSL_SYSCALL) || t->p_stat != SSTOP) {
- error = EINVAL;
- break;
- }
- SET(t->p_slflag, PSL_SYSCALLEMU);
- break;
-
- case PT_KILL:
- /* just send the process a KILL signal. */
- signo = SIGKILL;
- goto sendsig; /* in PT_CONTINUE, above. */
-
- case PT_ATTACH:
- /*
- * Go ahead and set the trace flag.
- * Save the old parent (it's reset in
- * _DETACH, and also in kern_exit.c:wait4()
- * Reparent the process so that the tracing
- * proc gets to see all the action.
- * Stop the target.
- */
- t->p_opptr = t->p_pptr;
- if (t->p_pptr != p) {
- struct proc *parent = t->p_pptr;
-
- if (parent->p_lock < t->p_lock) {
- if (!mutex_tryenter(parent->p_lock)) {
- mutex_exit(t->p_lock);
- mutex_enter(parent->p_lock);
- mutex_enter(t->p_lock);
- }
- } else if (parent->p_lock > t->p_lock) {
- mutex_enter(parent->p_lock);
- }
- parent->p_slflag |= PSL_CHTRACED;
- proc_reparent(t, p);
- if (parent->p_lock != t->p_lock)
- mutex_exit(parent->p_lock);
- }
- SET(t->p_slflag, PSL_TRACED);
- signo = SIGSTOP;
- goto sendsig;
-
- case PT_GET_EVENT_MASK:
- if (data != sizeof(pe)) {
- DPRINTF(("ptrace(%d): %d != %zu\n", req,
- 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, addr, sizeof(pe));
- break;
-
- case PT_SET_EVENT_MASK:
- if (data != sizeof(pe)) {
- DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
- sizeof(pe)));
- error = EINVAL;
- break;
- }
- if ((error = copyin(addr, &pe, sizeof(pe))) != 0)
- return error;
- if (pe.pe_set_event & PTRACE_FORK)
- SET(t->p_slflag, PSL_TRACEFORK);
- else
- CLR(t->p_slflag, PSL_TRACEFORK);
- break;
-
- case PT_GET_PROCESS_STATE:
- if (data != sizeof(ps)) {
- DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
- sizeof(ps)));
- error = EINVAL;
- break;
- }
- memset(&ps, 0, sizeof(ps));
- if (t->p_fpid) {
- ps.pe_report_event = PTRACE_FORK;
- ps.pe_other_pid = t->p_fpid;
- }
- error = copyout(&ps, addr, sizeof(ps));
- break;
-
- case PT_LWPINFO:
- if (data != sizeof(pl)) {
- DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
- sizeof(pl)));
- error = EINVAL;
- break;
- }
- error = copyin(addr, &pl, sizeof(pl));
- if (error)
- break;
- tmp = pl.pl_lwpid;
- lwp_delref(lt);
- mutex_enter(t->p_lock);
- if (tmp == 0)
- lt = lwp_find_first(t);
- else {
- lt = lwp_find(t, tmp);
- if (lt == NULL) {
- mutex_exit(t->p_lock);
- error = ESRCH;
- break;
- }
- lt = LIST_NEXT(lt, l_sibling);
- }
- while (lt != NULL && !lwp_alive(lt))
- lt = LIST_NEXT(lt, l_sibling);
- pl.pl_lwpid = 0;
- pl.pl_event = 0;
- if (lt) {
- lwp_addref(lt);
- pl.pl_lwpid = lt->l_lid;
- if (lt->l_lid == t->p_sigctx.ps_lwp)
- pl.pl_event = PL_EVENT_SIGNAL;
- }
- mutex_exit(t->p_lock);
-
- error = copyout(&pl, addr, sizeof(pl));
- break;
-
-#ifdef PT_SETREGS
- case PT_SETREGS:
- write = 1;
-#endif
-#ifdef PT_GETREGS
- case PT_GETREGS:
- /* write = 0 done above. */
-#endif
-#if defined(PT_SETREGS) || defined(PT_GETREGS)
- tmp = data;
- if (tmp != 0 && t->p_nlwps > 1) {
- lwp_delref(lt);
- mutex_enter(t->p_lock);
- lt = lwp_find(t, tmp);
- if (lt == NULL) {
- mutex_exit(t->p_lock);
- error = ESRCH;
- break;
- }
- lwp_addref(lt);
- mutex_exit(t->p_lock);
- }
- if (!process_validregs(lt))
- error = EINVAL;
- else {
- error = proc_vmspace_getref(p, &vm);
- if (error)
- break;
- 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 = iov.iov_len;
- uio.uio_rw = write ? UIO_WRITE : UIO_READ;
- uio.uio_vmspace = vm;
-
- error = ptm->ptm_doregs(l, lt, &uio);
- uvmspace_free(vm);
- }
- break;
-#endif
-
-#ifdef PT_SETFPREGS
- case PT_SETFPREGS:
- write = 1;
-#endif
-#ifdef PT_GETFPREGS
- case PT_GETFPREGS:
- /* write = 0 done above. */
-#endif
-#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
- tmp = data;
- if (tmp != 0 && t->p_nlwps > 1) {
- lwp_delref(lt);
- mutex_enter(t->p_lock);
- lt = lwp_find(t, tmp);
- if (lt == NULL) {
- mutex_exit(t->p_lock);
- error = ESRCH;
- break;
- }
- lwp_addref(lt);
- mutex_exit(t->p_lock);
- }
- if (!process_validfpregs(lt))
- error = EINVAL;
- else {
- error = proc_vmspace_getref(p, &vm);
- if (error)
- break;
- 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 = iov.iov_len;
- uio.uio_rw = write ? UIO_WRITE : UIO_READ;
- uio.uio_vmspace = vm;
-
- error = ptm->ptm_dofpregs(l, lt, &uio);
- uvmspace_free(vm);
- }
- break;
-#endif
-
-#ifdef __HAVE_PTRACE_MACHDEP
- PTRACE_MACHDEP_REQUEST_CASES
- error = ptrace_machdep_dorequest(l, lt, req, addr, data);
- break;
-#endif
- }
-
- if (pheld) {
- mutex_exit(t->p_lock);
- mutex_exit(proc_lock);
- }
- if (lt != NULL)
- lwp_delref(lt);
- rw_exit(&t->p_reflock);
-
- return error;
-}
-
-int
-process_doregs(struct lwp *curl /*tracer*/,
- struct lwp *l /*traced*/,
- struct uio *uio)
-{
-#if defined(PT_GETREGS) || defined(PT_SETREGS)
- int error;
- 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;
-
- 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);
- 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);
- }
-
- uio->uio_offset = 0;
- return error;
-#else
- return EINVAL;
-#endif
-}
-
-int
-process_validregs(struct lwp *l)
-{
-
-#if defined(PT_SETREGS) || defined(PT_GETREGS)
- return (l->l_flag & LW_SYSTEM) == 0;
-#else
- return 0;
-#endif
-}
-
-int
-process_dofpregs(struct lwp *curl /*tracer*/,
- struct lwp *l /*traced*/,
- struct uio *uio)
-{
-#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
- int error;
- 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;
-
- kv += uio->uio_offset;
- kl -= uio->uio_offset;
- if (kl > uio->uio_resid)
- kl = uio->uio_resid;
-
- 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);
- }
- uio->uio_offset = 0;
- return error;
-#else
- return EINVAL;
-#endif
-}
-
-int
-process_validfpregs(struct lwp *l)
-{
-
-#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
- return (l->l_flag & LW_SYSTEM) == 0;
-#else
- return 0;
-#endif
-}
-#endif /* PTRACE */
-
-#if defined(KTRACE) || defined(PTRACE)
+#if defined(KTRACE) || defined(PTRACE_HOOKS)
int
process_domem(struct lwp *curl /*tracer*/,
struct lwp *l /*traced*/,
@@ -1156,9 +188,7 @@ process_domem(struct lwp *curl /*tracer*
#endif
return error;
}
-#endif /* KTRACE || PTRACE */
-#if defined(KTRACE) || defined(PTRACE)
void
process_stoptrace(void)
{
@@ -1186,32 +216,16 @@ process_stoptrace(void)
}
mutex_exit(p->p_lock);
}
-#endif /* KTRACE || PTRACE */
+#endif /* KTRACE || PTRACE_HOOKS */
-#ifdef PTRACE
-static int
-process_auxv_offset(struct proc *p, struct uio *uio)
+/*
+ * Dummy routine so that ptrace_common module will fail to load if this
+ * routine is not defined.
+ */
+#if defined(PTRACE_HOOKS)
+void
+ptrace_hooks(void)
{
- struct ps_strings pss;
- int error;
- off_t off = (off_t)p->p_psstrp;
- if ((error = copyin_psstrings(p, &pss)) != 0)
- return error;
-
- if (pss.ps_envstr == NULL)
- return EIO;
-
- uio->uio_offset += (off_t)(vaddr_t)(pss.ps_envstr + pss.ps_nenvstr + 1);
-#ifdef __MACHINE_STACK_GROWS_UP
- if (uio->uio_offset < off)
- return EIO;
-#else
- if (uio->uio_offset > off)
- return EIO;
- if ((uio->uio_offset + uio->uio_resid) > off)
- uio->uio_resid = off - uio->uio_offset;
-#endif
- return 0;
}
#endif
Index: src/sys/kern/syscalls.master
diff -u src/sys/kern/syscalls.master:1.285 src/sys/kern/syscalls.master:1.286
--- src/sys/kern/syscalls.master:1.285 Sun Jul 3 14:24:59 2016
+++ src/sys/kern/syscalls.master Wed Nov 2 00:11:59 2016
@@ -1,4 +1,4 @@
- $NetBSD: syscalls.master,v 1.285 2016/07/03 14:24:59 christos Exp $
+ $NetBSD: syscalls.master,v 1.286 2016/11/02 00:11:59 pgoyette Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -100,11 +100,12 @@
21 COMPAT_40 MODULAR compat \
{ int|sys||mount(const char *type, const char *path, \
int flags, void *data); }
-22 STD RUMP { int|sys||unmount(const char *path, int flags); }
+22 STD RUMP { int|sys||unmount(const char *path, int flags); }
23 STD RUMP { int|sys||setuid(uid_t uid); }
24 NOERR RUMP { uid_t|sys||getuid_with_euid(void); } getuid
25 NOERR RUMP { uid_t|sys||geteuid(void); }
-26 STD { int|sys||ptrace(int req, pid_t pid, void *addr, \
+26 STD MODULAR ptrace \
+ { int|sys||ptrace(int req, pid_t pid, void *addr, \
int data); }
27 STD RUMP { ssize_t|sys||recvmsg(int s, struct msghdr *msg, \
int flags); }
Index: src/sys/miscfs/procfs/files.procfs
diff -u src/sys/miscfs/procfs/files.procfs:1.9 src/sys/miscfs/procfs/files.procfs:1.10
--- src/sys/miscfs/procfs/files.procfs:1.9 Sat Oct 11 06:42:20 2014
+++ src/sys/miscfs/procfs/files.procfs Wed Nov 2 00:12:00 2016
@@ -1,6 +1,6 @@
-# $NetBSD: files.procfs,v 1.9 2014/10/11 06:42:20 uebayasi Exp $
+# $NetBSD: files.procfs,v 1.10 2016/11/02 00:12:00 pgoyette Exp $
-deffs PROCFS: PTRACE
+deffs PROCFS: PTRACE_HOOKS
define procfs: vfs
file miscfs/procfs/procfs_cmdline.c procfs
Index: src/sys/modules/Makefile
diff -u src/sys/modules/Makefile:1.181 src/sys/modules/Makefile:1.182
--- src/sys/modules/Makefile:1.181 Wed Oct 19 09:44:01 2016
+++ src/sys/modules/Makefile Wed Nov 2 00:12:00 2016
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.181 2016/10/19 09:44:01 skrll Exp $
+# $NetBSD: Makefile,v 1.182 2016/11/02 00:12:00 pgoyette Exp $
.include <bsd.own.mk>
@@ -96,6 +96,8 @@ SUBDIR+= pf
SUBDIR+= ppp_bsdcomp
SUBDIR+= ppp_deflate
SUBDIR+= procfs
+SUBDIR+= ptrace
+SUBDIR+= ptrace_common
SUBDIR+= ptyfs
SUBDIR+= puffs
SUBDIR+= putter
Index: src/sys/sys/ptrace.h
diff -u src/sys/sys/ptrace.h:1.47 src/sys/sys/ptrace.h:1.48
--- src/sys/sys/ptrace.h:1.47 Wed Oct 19 09:44:01 2016
+++ src/sys/sys/ptrace.h Wed Nov 2 00:12:00 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.47 2016/10/19 09:44:01 skrll Exp $ */
+/* $NetBSD: ptrace.h,v 1.48 2016/11/02 00:12:00 pgoyette Exp $ */
/*-
* Copyright (c) 1984, 1993
@@ -146,7 +146,9 @@ struct ptrace_methods {
int (*ptm_dofpregs)(struct lwp *, struct lwp *, struct uio *);
};
-void ptrace_init(void);
+int ptrace_init(void);
+int ptrace_fini(void);
+void ptrace_hooks(void);
int process_doregs(struct lwp *, struct lwp *, struct uio *);
int process_validregs(struct lwp *);
Added files:
Index: src/sys/kern/sys_ptrace.c
diff -u /dev/null src/sys/kern/sys_ptrace.c:1.1
--- /dev/null Wed Nov 2 00:12:00 2016
+++ src/sys/kern/sys_ptrace.c Wed Nov 2 00:11:59 2016
@@ -0,0 +1,296 @@
+/* $NetBSD: sys_ptrace.c,v 1.1 2016/11/02 00:11:59 pgoyette Exp $ */
+
+/*-
+ * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * 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.
+ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93
+ */
+
+/*-
+ * Copyright (c) 1993 Jan-Simon Pendry.
+ * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * References:
+ * (1) Bach's "The Design of the UNIX Operating System",
+ * (2) sys/miscfs/procfs from UCB's 4.4BSD-Lite distribution,
+ * (3) the "4.4BSD Programmer's Reference Manual" published
+ * by USENIX and O'Reilly & Associates.
+ * The 4.4BSD PRM does a reasonably good job of documenting what the various
+ * ptrace() requests should actually do, and its text is quoted several times
+ * in this file.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace.c,v 1.1 2016/11/02 00:11:59 pgoyette Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_ptrace.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/exec.h>
+#include <sys/pax.h>
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/ras.h>
+#include <sys/kmem.h>
+#include <sys/kauth.h>
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
+#include <sys/syscallvar.h>
+#include <sys/syscall.h>
+#include <sys/module.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/reg.h>
+
+/*
+ * PTRACE methods
+ */
+
+static int ptrace_copyinpiod(struct ptrace_io_desc *, const void *);
+static void ptrace_copyoutpiod(const struct ptrace_io_desc *, void *);
+static int ptrace_doregs(struct lwp *, struct lwp *, struct uio *);
+static int ptrace_dofpregs(struct lwp *, struct lwp *, struct uio *);
+
+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));
+}
+
+int
+ptrace_doregs(struct lwp *curl /*tracer*/,
+ struct lwp *l /*traced*/,
+ struct uio *uio)
+{
+#if defined(PT_GETREGS) || defined(PT_SETREGS)
+ int error;
+ 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;
+
+ 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);
+ 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);
+ }
+
+ uio->uio_offset = 0;
+ return error;
+#else
+ return EINVAL;
+#endif
+}
+
+int
+ptrace_dofpregs(struct lwp *curl /*tracer*/,
+ struct lwp *l /*traced*/,
+ struct uio *uio)
+{
+#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
+ int error;
+ 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;
+
+ kv += uio->uio_offset;
+ kl -= uio->uio_offset;
+ if (kl > uio->uio_resid)
+ kl = uio->uio_resid;
+
+ 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);
+ }
+ uio->uio_offset = 0;
+ return error;
+#else
+ return EINVAL;
+#endif
+}
+
+static struct ptrace_methods native_ptm = {
+ .ptm_copyinpiod = ptrace_copyinpiod,
+ .ptm_copyoutpiod = ptrace_copyoutpiod,
+ .ptm_doregs = ptrace_doregs,
+ .ptm_dofpregs = ptrace_dofpregs,
+};
+
+static const struct syscall_package ptrace_syscalls[] = {
+ { SYS_ptrace, 0, (sy_call_t *)sys_ptrace },
+ { 0, 0, NULL },
+};
+
+/*
+ * Process debugging system call.
+ */
+int
+sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval)
+{
+ /* {
+ syscallarg(int) req;
+ syscallarg(pid_t) pid;
+ 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);
+}
+
+#define DEPS "ptrace_common"
+
+MODULE(MODULE_CLASS_EXEC, ptrace, DEPS);
+
+static int
+ptrace_modcmd(modcmd_t cmd, void *arg)
+{
+ int error;
+
+ switch (cmd) {
+ case MODULE_CMD_INIT:
+ error = syscall_establish(&emul_netbsd, ptrace_syscalls);
+ break;
+ case MODULE_CMD_FINI:
+ error = syscall_disestablish(&emul_netbsd, ptrace_syscalls);
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return error;
+}
Index: src/sys/kern/sys_ptrace_common.c
diff -u /dev/null src/sys/kern/sys_ptrace_common.c:1.1
--- /dev/null Wed Nov 2 00:12:00 2016
+++ src/sys/kern/sys_ptrace_common.c Wed Nov 2 00:11:59 2016
@@ -0,0 +1,1171 @@
+/* $NetBSD: sys_ptrace_common.c,v 1.1 2016/11/02 00:11:59 pgoyette Exp $ */
+
+/*-
+ * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * 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.
+ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93
+ */
+
+/*-
+ * Copyright (c) 1993 Jan-Simon Pendry.
+ * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * References:
+ * (1) Bach's "The Design of the UNIX Operating System",
+ * (2) sys/miscfs/procfs from UCB's 4.4BSD-Lite distribution,
+ * (3) the "4.4BSD Programmer's Reference Manual" published
+ * by USENIX and O'Reilly & Associates.
+ * The 4.4BSD PRM does a reasonably good job of documenting what the various
+ * ptrace() requests should actually do, and its text is quoted several times
+ * in this file.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.1 2016/11/02 00:11:59 pgoyette 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>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/exec.h>
+#include <sys/pax.h>
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/ras.h>
+#include <sys/kmem.h>
+#include <sys/kauth.h>
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
+#include <sys/module.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/reg.h>
+
+#ifdef PTRACE
+
+# ifdef DEBUG
+# define DPRINTF(a) uprintf a
+# else
+# define DPRINTF(a)
+# endif
+
+static kauth_listener_t ptrace_listener;
+static int process_auxv_offset(struct proc *, struct uio *);
+
+#if 0
+static int ptrace_cbref;
+static kmutex_t ptrace_mtx;
+static kcondvar_t ptrace_cv;
+#endif
+
+static int
+ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
+ void *arg0, void *arg1, void *arg2, void *arg3)
+{
+ struct proc *p;
+ int result;
+
+ result = KAUTH_RESULT_DEFER;
+ p = arg0;
+
+#if 0
+ mutex_enter(&ptrace_mtx);
+ ptrace_cbref++;
+ mutex_exit(&ptrace_mtx);
+#endif
+ if (action != KAUTH_PROCESS_PTRACE)
+ goto out;
+
+ switch ((u_long)arg1) {
+ case PT_TRACE_ME:
+ case PT_ATTACH:
+ case PT_WRITE_I:
+ case PT_WRITE_D:
+ case PT_READ_I:
+ case PT_READ_D:
+ case PT_IO:
+#ifdef PT_GETREGS
+ case PT_GETREGS:
+#endif
+#ifdef PT_SETREGS
+ case PT_SETREGS:
+#endif
+#ifdef PT_GETFPREGS
+ case PT_GETFPREGS:
+#endif
+#ifdef PT_SETFPREGS
+ case PT_SETFPREGS:
+#endif
+ case PT_SET_EVENT_MASK:
+ case PT_GET_EVENT_MASK:
+ case PT_GET_PROCESS_STATE:
+#ifdef __HAVE_PTRACE_MACHDEP
+ PTRACE_MACHDEP_REQUEST_CASES
+#endif
+ if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) ||
+ ISSET(p->p_flag, PK_SUGID)) {
+ break;
+ }
+
+ result = KAUTH_RESULT_ALLOW;
+
+ break;
+
+#ifdef PT_STEP
+ case PT_STEP:
+#endif
+ case PT_CONTINUE:
+ case PT_KILL:
+ case PT_DETACH:
+ case PT_LWPINFO:
+ case PT_SYSCALL:
+ case PT_SYSCALLEMU:
+ case PT_DUMPCORE:
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ break;
+ }
+
+ out:
+#if 0
+ mutex_enter(&ptrace_mtx);
+ if (--ptrace_cbref == 0)
+ cv_broadcast(&ptrace_cv);
+ mutex_exit(&ptrace_mtx);
+#endif
+
+ return result;
+}
+
+int
+ptrace_init(void)
+{
+
+#if 0
+ mutex_init(&ptrace_mtx, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&ptrace_cv, "ptracecb");
+ ptrace_cbref = 0;
+#endif
+ ptrace_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
+ ptrace_listener_cb, NULL);
+ return 0;
+}
+
+int
+ptrace_fini(void)
+{
+
+ kauth_unlisten_scope(ptrace_listener);
+
+#if 0
+ /* Make sure no-one is executing our kauth listener */
+
+ mutex_enter(&ptrace_mtx);
+ while (ptrace_cbref != 0)
+ cv_wait(&ptrace_cv, &ptrace_mtx);
+ mutex_exit(&ptrace_mtx);
+ mutex_destroy(&ptrace_mtx);
+ cv_destroy(&ptrace_cv);
+#endif
+
+ return 0;
+}
+
+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
+ struct lwp *lt2;
+#endif
+ struct proc *t; /* target process */
+ struct uio uio;
+ struct iovec iov;
+ struct ptrace_io_desc piod;
+ struct ptrace_event pe;
+ struct ptrace_state ps;
+ struct ptrace_lwpinfo pl;
+ struct vmspace *vm;
+ int error, write, tmp, pheld;
+ int signo = 0;
+ int resume_all;
+ ksiginfo_t ksi;
+ char *path;
+ int len = 0;
+ error = 0;
+
+ /*
+ * If attaching or detaching, we need to get a write hold on the
+ * proclist lock so that we can re-parent the target process.
+ */
+ mutex_enter(proc_lock);
+
+ /* "A foolish consistency..." XXX */
+ if (req == PT_TRACE_ME) {
+ t = p;
+ mutex_enter(t->p_lock);
+ } else {
+ /* Find the process we're supposed to be operating on. */
+ t = proc_find(pid);
+ if (t == NULL) {
+ mutex_exit(proc_lock);
+ return ESRCH;
+ }
+
+ /* XXX-elad */
+ mutex_enter(t->p_lock);
+ error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
+ t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
+ if (error) {
+ mutex_exit(proc_lock);
+ mutex_exit(t->p_lock);
+ return ESRCH;
+ }
+ }
+
+ /*
+ * Grab a reference on the process to prevent it from execing or
+ * exiting.
+ */
+ if (!rw_tryenter(&t->p_reflock, RW_READER)) {
+ mutex_exit(proc_lock);
+ mutex_exit(t->p_lock);
+ return EBUSY;
+ }
+
+ /* Make sure we can operate on it. */
+ switch (req) {
+ case PT_TRACE_ME:
+ /* Saying that you're being traced is always legal. */
+ break;
+
+ case PT_ATTACH:
+ /*
+ * You can't attach to a process if:
+ * (1) it's the process that's doing the attaching,
+ */
+ if (t->p_pid == p->p_pid) {
+ error = EINVAL;
+ break;
+ }
+
+ /*
+ * (2) it's a system process
+ */
+ if (t->p_flag & PK_SYSTEM) {
+ error = EPERM;
+ break;
+ }
+
+ /*
+ * (3) it's already being traced, or
+ */
+ if (ISSET(t->p_slflag, PSL_TRACED)) {
+ error = EBUSY;
+ break;
+ }
+
+ /*
+ * (4) the tracer is chrooted, and its root directory is
+ * not at or above the root directory of the tracee
+ */
+ mutex_exit(t->p_lock); /* XXXSMP */
+ tmp = proc_isunder(t, l);
+ mutex_enter(t->p_lock); /* XXXSMP */
+ if (!tmp) {
+ error = EPERM;
+ break;
+ }
+ break;
+
+ case PT_READ_I:
+ case PT_READ_D:
+ case PT_WRITE_I:
+ case PT_WRITE_D:
+ case PT_IO:
+#ifdef PT_GETREGS
+ case PT_GETREGS:
+#endif
+#ifdef PT_SETREGS
+ case PT_SETREGS:
+#endif
+#ifdef PT_GETFPREGS
+ case PT_GETFPREGS:
+#endif
+#ifdef PT_SETFPREGS
+ case PT_SETFPREGS:
+#endif
+#ifdef __HAVE_PTRACE_MACHDEP
+ PTRACE_MACHDEP_REQUEST_CASES
+#endif
+ /*
+ * You can't read/write the memory or registers of a process
+ * if the tracer is chrooted, and its root directory is not at
+ * or above the root directory of the tracee.
+ */
+ mutex_exit(t->p_lock); /* XXXSMP */
+ tmp = proc_isunder(t, l);
+ mutex_enter(t->p_lock); /* XXXSMP */
+ if (!tmp) {
+ error = EPERM;
+ break;
+ }
+ /*FALLTHROUGH*/
+
+ case PT_CONTINUE:
+ case PT_KILL:
+ case PT_DETACH:
+ case PT_LWPINFO:
+ case PT_SYSCALL:
+ case PT_SYSCALLEMU:
+ case PT_DUMPCORE:
+#ifdef PT_STEP
+ case PT_STEP:
+#endif
+ case PT_SET_EVENT_MASK:
+ case PT_GET_EVENT_MASK:
+ case PT_GET_PROCESS_STATE:
+ /*
+ * You can't do what you want to the process if:
+ * (1) It's not being traced at all,
+ */
+ if (!ISSET(t->p_slflag, PSL_TRACED)) {
+ error = EPERM;
+ break;
+ }
+
+ /*
+ * (2) it's being traced by procfs (which has
+ * different signal delivery semantics),
+ */
+ if (ISSET(t->p_slflag, PSL_FSTRACE)) {
+ DPRINTF(("file system traced\n"));
+ error = EBUSY;
+ break;
+ }
+
+ /*
+ * (3) it's not being traced by _you_, or
+ */
+ if (t->p_pptr != p) {
+ DPRINTF(("parent %d != %d\n", t->p_pptr->p_pid,
+ p->p_pid));
+ error = EBUSY;
+ break;
+ }
+
+ /*
+ * (4) it's not currently stopped.
+ */
+ if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) {
+ DPRINTF(("stat %d flag %d\n", t->p_stat,
+ !t->p_waited));
+ error = EBUSY;
+ break;
+ }
+ break;
+
+ default: /* It was not a legal request. */
+ error = EINVAL;
+ break;
+ }
+
+ if (error == 0) {
+ error = kauth_authorize_process(l->l_cred,
+ KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req),
+ NULL, NULL);
+ }
+ if (error == 0) {
+ lt = lwp_find_first(t);
+ if (lt == NULL)
+ error = ESRCH;
+ }
+
+ if (error != 0) {
+ mutex_exit(proc_lock);
+ mutex_exit(t->p_lock);
+ rw_exit(&t->p_reflock);
+ return error;
+ }
+
+ /* Do single-step fixup if needed. */
+ FIX_SSTEP(t);
+ KASSERT(lt != NULL);
+ lwp_addref(lt);
+
+ /*
+ * Which locks do we need held? XXX Ugly.
+ */
+ switch (req) {
+#ifdef PT_STEP
+ case PT_STEP:
+#endif
+ case PT_CONTINUE:
+ case PT_DETACH:
+ case PT_KILL:
+ case PT_SYSCALL:
+ case PT_SYSCALLEMU:
+ case PT_ATTACH:
+ case PT_TRACE_ME:
+ pheld = 1;
+ break;
+ default:
+ mutex_exit(proc_lock);
+ mutex_exit(t->p_lock);
+ pheld = 0;
+ break;
+ }
+
+ /* Now do the operation. */
+ write = 0;
+ *retval = 0;
+ tmp = 0;
+ resume_all = 1;
+
+ switch (req) {
+ case PT_TRACE_ME:
+ /* Just set the trace flag. */
+ SET(t->p_slflag, PSL_TRACED);
+ t->p_opptr = t->p_pptr;
+ break;
+
+ case PT_WRITE_I: /* XXX no separate I and D spaces */
+ case PT_WRITE_D:
+#if defined(__HAVE_RAS)
+ /*
+ * Can't write to a RAS
+ */
+ if (ras_lookup(t, addr) != (void *)-1) {
+ error = EACCES;
+ break;
+ }
+#endif
+ write = 1;
+ tmp = data;
+ /* FALLTHROUGH */
+
+ case PT_READ_I: /* XXX no separate I and D spaces */
+ case PT_READ_D:
+ /* write = 0 done above. */
+ iov.iov_base = (void *)&tmp;
+ iov.iov_len = sizeof(tmp);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ 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);
+
+ error = process_domem(l, lt, &uio);
+ if (!write)
+ *retval = tmp;
+ break;
+
+ case PT_IO:
+ error = ptm->ptm_copyinpiod(&piod, addr);
+ if (error)
+ break;
+
+ iov.iov_base = piod.piod_addr;
+ iov.iov_len = piod.piod_len;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)(unsigned long)piod.piod_offs;
+ uio.uio_resid = piod.piod_len;
+
+ switch (piod.piod_op) {
+ case PIOD_READ_D:
+ case PIOD_READ_I:
+ uio.uio_rw = UIO_READ;
+ break;
+ case PIOD_WRITE_D:
+ case PIOD_WRITE_I:
+ /*
+ * Can't write to a RAS
+ */
+ if (ras_lookup(t, addr) != (void *)-1) {
+ return EACCES;
+ }
+ uio.uio_rw = UIO_WRITE;
+ break;
+ case PIOD_READ_AUXV:
+ req = PT_READ_D;
+ uio.uio_rw = UIO_READ;
+ tmp = t->p_execsw->es_arglen * PROC_PTRSZ(t);
+ if (uio.uio_offset > tmp)
+ return EIO;
+ if (uio.uio_resid > tmp - uio.uio_offset)
+ uio.uio_resid = tmp - uio.uio_offset;
+ piod.piod_len = iov.iov_len = uio.uio_resid;
+ error = process_auxv_offset(t, &uio);
+ if (error)
+ return error;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error)
+ break;
+ error = proc_vmspace_getref(l->l_proc, &vm);
+ if (error)
+ break;
+ uio.uio_vmspace = vm;
+
+ error = process_domem(l, lt, &uio);
+ piod.piod_len -= uio.uio_resid;
+ (void) ptm->ptm_copyoutpiod(&piod, addr);
+
+ uvmspace_free(vm);
+ break;
+
+ case PT_DUMPCORE:
+ if ((path = addr) != NULL) {
+ char *dst;
+ len = data;
+
+ if (len < 0 || len >= MAXPATHLEN) {
+ error = EINVAL;
+ break;
+ }
+ dst = kmem_alloc(len + 1, KM_SLEEP);
+ if ((error = copyin(path, dst, len)) != 0) {
+ kmem_free(dst, len + 1);
+ break;
+ }
+ path = dst;
+ path[len] = '\0';
+ }
+ error = (*coredump_vec)(lt, path);
+ if (path)
+ kmem_free(path, len + 1);
+ break;
+
+#ifdef PT_STEP
+ case PT_STEP:
+ /*
+ * From the 4.4BSD PRM:
+ * "Execution continues as in request PT_CONTINUE; however
+ * as soon as possible after execution of at least one
+ * instruction, execution stops again. [ ... ]"
+ */
+#endif
+ case PT_CONTINUE:
+ case PT_SYSCALL:
+ case PT_DETACH:
+ if (req == PT_SYSCALL) {
+ if (!ISSET(t->p_slflag, PSL_SYSCALL)) {
+ SET(t->p_slflag, PSL_SYSCALL);
+#ifdef __HAVE_SYSCALL_INTERN
+ (*t->p_emul->e_syscall_intern)(t);
+#endif
+ }
+ } else {
+ if (ISSET(t->p_slflag, PSL_SYSCALL)) {
+ CLR(t->p_slflag, PSL_SYSCALL);
+#ifdef __HAVE_SYSCALL_INTERN
+ (*t->p_emul->e_syscall_intern)(t);
+#endif
+ }
+ }
+ t->p_trace_enabled = trace_is_enabled(t);
+
+ /*
+ * Pick up the LWPID, if supplied. There are two cases:
+ * data < 0 : step or continue single thread, lwp = -data
+ * data > 0 in PT_STEP : step this thread, continue others
+ * For operations other than PT_STEP, data > 0 means
+ * data is the signo to deliver to the process.
+ */
+ tmp = data;
+ if (tmp >= 0) {
+#ifdef PT_STEP
+ if (req == PT_STEP)
+ signo = 0;
+ else
+#endif
+ {
+ signo = tmp;
+ tmp = 0; /* don't search for LWP */
+ }
+ } else
+ tmp = -tmp;
+
+ if (tmp > 0) {
+ if (req == PT_DETACH) {
+ error = EINVAL;
+ break;
+ }
+ lwp_delref2 (lt);
+ lt = lwp_find(t, tmp);
+ if (lt == NULL) {
+ error = ESRCH;
+ break;
+ }
+ lwp_addref(lt);
+ resume_all = 0;
+ signo = 0;
+ }
+
+ /*
+ * From the 4.4BSD PRM:
+ * "The data argument is taken as a signal number and the
+ * child's execution continues at location addr as if it
+ * incurred that signal. Normally the signal number will
+ * be either 0 to indicate that the signal that caused the
+ * stop should be ignored, or that value fetched out of
+ * the process's image indicating which signal caused
+ * the stop. If addr is (int *)1 then execution continues
+ * from where it stopped."
+ */
+
+ /* Check that the data is a valid signal number or zero. */
+ if (signo < 0 || signo >= NSIG) {
+ error = EINVAL;
+ break;
+ }
+
+ /* If the address parameter is not (int *)1, set the pc. */
+ if ((int *)addr != (int *)1) {
+ error = process_set_pc(lt, addr);
+ if (error != 0)
+ break;
+ }
+#ifdef PT_STEP
+ /*
+ * Arrange for a single-step, if that's requested and possible.
+ * More precisely, set the single step status as requested for
+ * the requested thread, and clear it for other threads.
+ */
+ LIST_FOREACH(lt2, &t->p_lwps, l_sibling) {
+ if (lt != lt2) {
+ lwp_lock(lt2);
+ process_sstep(lt2, 0);
+ lwp_unlock(lt2);
+ }
+ }
+ error = process_sstep(lt, req == PT_STEP);
+ if (error)
+ break;
+#endif
+ if (req == PT_DETACH) {
+ CLR(t->p_slflag, PSL_TRACED|PSL_FSTRACE|PSL_SYSCALL);
+
+ /* give process back to original parent or init */
+ if (t->p_opptr != t->p_pptr) {
+ struct proc *pp = t->p_opptr;
+ proc_reparent(t, pp ? pp : initproc);
+ }
+
+ /* not being traced any more */
+ t->p_opptr = NULL;
+ }
+ sendsig:
+ t->p_fpid = 0;
+ /* Finally, deliver the requested signal (or none). */
+ if (t->p_stat == SSTOP) {
+ /*
+ * Unstop the process. If it needs to take a
+ * signal, make all efforts to ensure that at
+ * an LWP runs to see it.
+ */
+ t->p_xsig = signo;
+ if (resume_all)
+ proc_unstop(t);
+ else
+ lwp_unstop(lt);
+ } else if (signo != 0) {
+ KSI_INIT_EMPTY(&ksi);
+ ksi.ksi_signo = signo;
+ kpsignal2(t, &ksi);
+ }
+ break;
+
+ case PT_SYSCALLEMU:
+ if (!ISSET(t->p_slflag, PSL_SYSCALL) || t->p_stat != SSTOP) {
+ error = EINVAL;
+ break;
+ }
+ SET(t->p_slflag, PSL_SYSCALLEMU);
+ break;
+
+ case PT_KILL:
+ /* just send the process a KILL signal. */
+ signo = SIGKILL;
+ goto sendsig; /* in PT_CONTINUE, above. */
+
+ case PT_ATTACH:
+ /*
+ * Go ahead and set the trace flag.
+ * Save the old parent (it's reset in
+ * _DETACH, and also in kern_exit.c:wait4()
+ * Reparent the process so that the tracing
+ * proc gets to see all the action.
+ * Stop the target.
+ */
+ t->p_opptr = t->p_pptr;
+ if (t->p_pptr != p) {
+ struct proc *parent = t->p_pptr;
+
+ if (parent->p_lock < t->p_lock) {
+ if (!mutex_tryenter(parent->p_lock)) {
+ mutex_exit(t->p_lock);
+ mutex_enter(parent->p_lock);
+ mutex_enter(t->p_lock);
+ }
+ } else if (parent->p_lock > t->p_lock) {
+ mutex_enter(parent->p_lock);
+ }
+ parent->p_slflag |= PSL_CHTRACED;
+ proc_reparent(t, p);
+ if (parent->p_lock != t->p_lock)
+ mutex_exit(parent->p_lock);
+ }
+ SET(t->p_slflag, PSL_TRACED);
+ signo = SIGSTOP;
+ goto sendsig;
+
+ case PT_GET_EVENT_MASK:
+ if (data != sizeof(pe)) {
+ DPRINTF(("ptrace(%d): %d != %zu\n", req,
+ 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, addr, sizeof(pe));
+ break;
+
+ case PT_SET_EVENT_MASK:
+ if (data != sizeof(pe)) {
+ DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
+ sizeof(pe)));
+ error = EINVAL;
+ break;
+ }
+ if ((error = copyin(addr, &pe, sizeof(pe))) != 0)
+ return error;
+ if (pe.pe_set_event & PTRACE_FORK)
+ SET(t->p_slflag, PSL_TRACEFORK);
+ else
+ CLR(t->p_slflag, PSL_TRACEFORK);
+ break;
+
+ case PT_GET_PROCESS_STATE:
+ if (data != sizeof(ps)) {
+ DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
+ sizeof(ps)));
+ error = EINVAL;
+ break;
+ }
+ memset(&ps, 0, sizeof(ps));
+ if (t->p_fpid) {
+ ps.pe_report_event = PTRACE_FORK;
+ ps.pe_other_pid = t->p_fpid;
+ }
+ error = copyout(&ps, addr, sizeof(ps));
+ break;
+
+ case PT_LWPINFO:
+ if (data != sizeof(pl)) {
+ DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
+ sizeof(pl)));
+ error = EINVAL;
+ break;
+ }
+ error = copyin(addr, &pl, sizeof(pl));
+ if (error)
+ break;
+ tmp = pl.pl_lwpid;
+ lwp_delref(lt);
+ mutex_enter(t->p_lock);
+ if (tmp == 0)
+ lt = lwp_find_first(t);
+ else {
+ lt = lwp_find(t, tmp);
+ if (lt == NULL) {
+ mutex_exit(t->p_lock);
+ error = ESRCH;
+ break;
+ }
+ lt = LIST_NEXT(lt, l_sibling);
+ }
+ while (lt != NULL && !lwp_alive(lt))
+ lt = LIST_NEXT(lt, l_sibling);
+ pl.pl_lwpid = 0;
+ pl.pl_event = 0;
+ if (lt) {
+ lwp_addref(lt);
+ pl.pl_lwpid = lt->l_lid;
+ if (lt->l_lid == t->p_sigctx.ps_lwp)
+ pl.pl_event = PL_EVENT_SIGNAL;
+ }
+ mutex_exit(t->p_lock);
+
+ error = copyout(&pl, addr, sizeof(pl));
+ break;
+
+#ifdef PT_SETREGS
+ case PT_SETREGS:
+ write = 1;
+#endif
+#ifdef PT_GETREGS
+ case PT_GETREGS:
+ /* write = 0 done above. */
+#endif
+#if defined(PT_SETREGS) || defined(PT_GETREGS)
+ tmp = data;
+ if (tmp != 0 && t->p_nlwps > 1) {
+ lwp_delref(lt);
+ mutex_enter(t->p_lock);
+ lt = lwp_find(t, tmp);
+ if (lt == NULL) {
+ mutex_exit(t->p_lock);
+ error = ESRCH;
+ break;
+ }
+ lwp_addref(lt);
+ mutex_exit(t->p_lock);
+ }
+ if (!process_validregs(lt))
+ error = EINVAL;
+ else {
+ error = proc_vmspace_getref(p, &vm);
+ if (error)
+ break;
+ 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 = iov.iov_len;
+ uio.uio_rw = write ? UIO_WRITE : UIO_READ;
+ uio.uio_vmspace = vm;
+
+ error = ptm->ptm_doregs(l, lt, &uio);
+ uvmspace_free(vm);
+ }
+ break;
+#endif
+
+#ifdef PT_SETFPREGS
+ case PT_SETFPREGS:
+ write = 1;
+#endif
+#ifdef PT_GETFPREGS
+ case PT_GETFPREGS:
+ /* write = 0 done above. */
+#endif
+#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
+ tmp = data;
+ if (tmp != 0 && t->p_nlwps > 1) {
+ lwp_delref(lt);
+ mutex_enter(t->p_lock);
+ lt = lwp_find(t, tmp);
+ if (lt == NULL) {
+ mutex_exit(t->p_lock);
+ error = ESRCH;
+ break;
+ }
+ lwp_addref(lt);
+ mutex_exit(t->p_lock);
+ }
+ if (!process_validfpregs(lt))
+ error = EINVAL;
+ else {
+ error = proc_vmspace_getref(p, &vm);
+ if (error)
+ break;
+ 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 = iov.iov_len;
+ uio.uio_rw = write ? UIO_WRITE : UIO_READ;
+ uio.uio_vmspace = vm;
+
+ error = ptm->ptm_dofpregs(l, lt, &uio);
+ uvmspace_free(vm);
+ }
+ break;
+#endif
+
+#ifdef __HAVE_PTRACE_MACHDEP
+ PTRACE_MACHDEP_REQUEST_CASES
+ error = ptrace_machdep_dorequest(l, lt, req, addr, data);
+ break;
+#endif
+ }
+
+ if (pheld) {
+ mutex_exit(t->p_lock);
+ mutex_exit(proc_lock);
+ }
+ if (lt != NULL)
+ lwp_delref(lt);
+ rw_exit(&t->p_reflock);
+
+ return error;
+}
+
+int
+process_doregs(struct lwp *curl /*tracer*/,
+ struct lwp *l /*traced*/,
+ struct uio *uio)
+{
+#if defined(PT_GETREGS) || defined(PT_SETREGS)
+ int error;
+ 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;
+
+ 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);
+ 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);
+ }
+
+ uio->uio_offset = 0;
+ return error;
+#else
+ return EINVAL;
+#endif
+}
+
+int
+process_validregs(struct lwp *l)
+{
+
+#if defined(PT_SETREGS) || defined(PT_GETREGS)
+ return (l->l_flag & LW_SYSTEM) == 0;
+#else
+ return 0;
+#endif
+}
+
+int
+process_dofpregs(struct lwp *curl /*tracer*/,
+ struct lwp *l /*traced*/,
+ struct uio *uio)
+{
+#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
+ int error;
+ 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;
+
+ kv += uio->uio_offset;
+ kl -= uio->uio_offset;
+ if (kl > uio->uio_resid)
+ kl = uio->uio_resid;
+
+ 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);
+ }
+ uio->uio_offset = 0;
+ return error;
+#else
+ return EINVAL;
+#endif
+}
+
+int
+process_validfpregs(struct lwp *l)
+{
+
+#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
+ return (l->l_flag & LW_SYSTEM) == 0;
+#else
+ return 0;
+#endif
+}
+
+static int
+process_auxv_offset(struct proc *p, struct uio *uio)
+{
+ struct ps_strings pss;
+ int error;
+ off_t off = (off_t)p->p_psstrp;
+
+ if ((error = copyin_psstrings(p, &pss)) != 0)
+ return error;
+
+ if (pss.ps_envstr == NULL)
+ return EIO;
+
+ uio->uio_offset += (off_t)(vaddr_t)(pss.ps_envstr + pss.ps_nenvstr + 1);
+#ifdef __MACHINE_STACK_GROWS_UP
+ if (uio->uio_offset < off)
+ return EIO;
+#else
+ if (uio->uio_offset > off)
+ return EIO;
+ if ((uio->uio_offset + uio->uio_resid) > off)
+ uio->uio_resid = off - uio->uio_offset;
+#endif
+ return 0;
+}
+#endif /* PTRACE */
+
+MODULE(MODULE_CLASS_EXEC, ptrace_common, "");
+
+static int
+ptrace_common_modcmd(modcmd_t cmd, void *arg)
+{
+ int error;
+
+ switch (cmd) {
+ case MODULE_CMD_INIT:
+ error = ptrace_init();
+ break;
+ case MODULE_CMD_FINI:
+ error = ptrace_fini();
+ break;
+ default:
+ ptrace_hooks();
+ error = ENOTTY;
+ break;
+ }
+ return error;
+}
+
Index: src/sys/modules/ptrace/Makefile
diff -u /dev/null src/sys/modules/ptrace/Makefile:1.1
--- /dev/null Wed Nov 2 00:12:00 2016
+++ src/sys/modules/ptrace/Makefile Wed Nov 2 00:12:00 2016
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.1 2016/11/02 00:12:00 pgoyette Exp $
+#
+.include "../Makefile.inc"
+
+.PATH: ${S}/kern
+
+CPPFLAGS+= -DPTRACE
+
+KMOD= ptrace
+SRCS= sys_ptrace.c
+
+.include <bsd.kmodule.mk>
Index: src/sys/modules/ptrace_common/Makefile
diff -u /dev/null src/sys/modules/ptrace_common/Makefile:1.1
--- /dev/null Wed Nov 2 00:12:00 2016
+++ src/sys/modules/ptrace_common/Makefile Wed Nov 2 00:12:00 2016
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.1 2016/11/02 00:12:00 pgoyette Exp $
+#
+.include "../Makefile.inc"
+
+.PATH: ${S}/kern
+
+CPPFLAGS+= -DPTRACE
+
+KMOD= ptrace_common
+SRCS= sys_ptrace_common.c
+
+.include <bsd.kmodule.mk>