1*5b38d912Schristos /* $NetBSD: sys_ptrace_common.c,v 1.96 2025/01/11 19:42:04 christos Exp $ */ 2a60b9909Spgoyette 3a60b9909Spgoyette /*- 4a60b9909Spgoyette * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. 5a60b9909Spgoyette * All rights reserved. 6a60b9909Spgoyette * 7a60b9909Spgoyette * This code is derived from software contributed to The NetBSD Foundation 8a60b9909Spgoyette * by Andrew Doran. 9a60b9909Spgoyette * 10a60b9909Spgoyette * Redistribution and use in source and binary forms, with or without 11a60b9909Spgoyette * modification, are permitted provided that the following conditions 12a60b9909Spgoyette * are met: 13a60b9909Spgoyette * 1. Redistributions of source code must retain the above copyright 14a60b9909Spgoyette * notice, this list of conditions and the following disclaimer. 15a60b9909Spgoyette * 2. Redistributions in binary form must reproduce the above copyright 16a60b9909Spgoyette * notice, this list of conditions and the following disclaimer in the 17a60b9909Spgoyette * documentation and/or other materials provided with the distribution. 18a60b9909Spgoyette * 19a60b9909Spgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20a60b9909Spgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21a60b9909Spgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22a60b9909Spgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23a60b9909Spgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24a60b9909Spgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25a60b9909Spgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26a60b9909Spgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27a60b9909Spgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28a60b9909Spgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29a60b9909Spgoyette * POSSIBILITY OF SUCH DAMAGE. 30a60b9909Spgoyette */ 31a60b9909Spgoyette 32a60b9909Spgoyette /*- 33a60b9909Spgoyette * Copyright (c) 1982, 1986, 1989, 1993 34a60b9909Spgoyette * The Regents of the University of California. All rights reserved. 35a60b9909Spgoyette * (c) UNIX System Laboratories, Inc. 36a60b9909Spgoyette * All or some portions of this file are derived from material licensed 37a60b9909Spgoyette * to the University of California by American Telephone and Telegraph 38a60b9909Spgoyette * Co. or Unix System Laboratories, Inc. and are reproduced herein with 39a60b9909Spgoyette * the permission of UNIX System Laboratories, Inc. 40a60b9909Spgoyette * 41a60b9909Spgoyette * This code is derived from software contributed to Berkeley by 42a60b9909Spgoyette * Jan-Simon Pendry. 43a60b9909Spgoyette * 44a60b9909Spgoyette * Redistribution and use in source and binary forms, with or without 45a60b9909Spgoyette * modification, are permitted provided that the following conditions 46a60b9909Spgoyette * are met: 47a60b9909Spgoyette * 1. Redistributions of source code must retain the above copyright 48a60b9909Spgoyette * notice, this list of conditions and the following disclaimer. 49a60b9909Spgoyette * 2. Redistributions in binary form must reproduce the above copyright 50a60b9909Spgoyette * notice, this list of conditions and the following disclaimer in the 51a60b9909Spgoyette * documentation and/or other materials provided with the distribution. 52a60b9909Spgoyette * 3. Neither the name of the University nor the names of its contributors 53a60b9909Spgoyette * may be used to endorse or promote products derived from this software 54a60b9909Spgoyette * without specific prior written permission. 55a60b9909Spgoyette * 56a60b9909Spgoyette * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57a60b9909Spgoyette * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58a60b9909Spgoyette * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59a60b9909Spgoyette * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60a60b9909Spgoyette * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61a60b9909Spgoyette * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62a60b9909Spgoyette * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63a60b9909Spgoyette * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64a60b9909Spgoyette * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65a60b9909Spgoyette * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66a60b9909Spgoyette * SUCH DAMAGE. 67a60b9909Spgoyette * 68a60b9909Spgoyette * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93 69a60b9909Spgoyette */ 70a60b9909Spgoyette 71a60b9909Spgoyette /*- 72a60b9909Spgoyette * Copyright (c) 1993 Jan-Simon Pendry. 73a60b9909Spgoyette * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved. 74a60b9909Spgoyette * 75a60b9909Spgoyette * This code is derived from software contributed to Berkeley by 76a60b9909Spgoyette * Jan-Simon Pendry. 77a60b9909Spgoyette * 78a60b9909Spgoyette * Redistribution and use in source and binary forms, with or without 79a60b9909Spgoyette * modification, are permitted provided that the following conditions 80a60b9909Spgoyette * are met: 81a60b9909Spgoyette * 1. Redistributions of source code must retain the above copyright 82a60b9909Spgoyette * notice, this list of conditions and the following disclaimer. 83a60b9909Spgoyette * 2. Redistributions in binary form must reproduce the above copyright 84a60b9909Spgoyette * notice, this list of conditions and the following disclaimer in the 85a60b9909Spgoyette * documentation and/or other materials provided with the distribution. 86a60b9909Spgoyette * 3. All advertising materials mentioning features or use of this software 87a60b9909Spgoyette * must display the following acknowledgement: 88a60b9909Spgoyette * This product includes software developed by the University of 89a60b9909Spgoyette * California, Berkeley and its contributors. 90a60b9909Spgoyette * 4. Neither the name of the University nor the names of its contributors 91a60b9909Spgoyette * may be used to endorse or promote products derived from this software 92a60b9909Spgoyette * without specific prior written permission. 93a60b9909Spgoyette * 94a60b9909Spgoyette * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 95a60b9909Spgoyette * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 96a60b9909Spgoyette * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 97a60b9909Spgoyette * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 98a60b9909Spgoyette * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 99a60b9909Spgoyette * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 100a60b9909Spgoyette * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 101a60b9909Spgoyette * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 102a60b9909Spgoyette * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 103a60b9909Spgoyette * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 104a60b9909Spgoyette * SUCH DAMAGE. 105a60b9909Spgoyette * 106a60b9909Spgoyette * from: @(#)sys_process.c 8.1 (Berkeley) 6/10/93 107a60b9909Spgoyette */ 108a60b9909Spgoyette 109a60b9909Spgoyette #include <sys/cdefs.h> 110*5b38d912Schristos __KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.96 2025/01/11 19:42:04 christos Exp $"); 111a60b9909Spgoyette 112a60b9909Spgoyette #ifdef _KERNEL_OPT 113a60b9909Spgoyette #include "opt_ptrace.h" 114a60b9909Spgoyette #include "opt_ktrace.h" 115a60b9909Spgoyette #include "opt_pax.h" 1162b14b22eSchristos #include "opt_compat_netbsd32.h" 117a60b9909Spgoyette #endif 118a60b9909Spgoyette 119d6abd869Schristos #if defined(__HAVE_COMPAT_NETBSD32) && !defined(COMPAT_NETBSD32) \ 120d6abd869Schristos && !defined(_RUMPKERNEL) 121d6abd869Schristos #define COMPAT_NETBSD32 122d6abd869Schristos #endif 123d6abd869Schristos 124a60b9909Spgoyette #include <sys/param.h> 125a60b9909Spgoyette #include <sys/systm.h> 126a60b9909Spgoyette #include <sys/proc.h> 127a60b9909Spgoyette #include <sys/errno.h> 128a60b9909Spgoyette #include <sys/exec.h> 129a60b9909Spgoyette #include <sys/pax.h> 130a60b9909Spgoyette #include <sys/ptrace.h> 131a60b9909Spgoyette #include <sys/uio.h> 132a60b9909Spgoyette #include <sys/ras.h> 133a60b9909Spgoyette #include <sys/kmem.h> 134a60b9909Spgoyette #include <sys/kauth.h> 135a60b9909Spgoyette #include <sys/mount.h> 136a60b9909Spgoyette #include <sys/syscallargs.h> 137484b4a02Skamil #include <sys/module.h> 138a60b9909Spgoyette #include <sys/condvar.h> 139a60b9909Spgoyette #include <sys/mutex.h> 14073844747Spgoyette #include <sys/compat_stub.h> 141a60b9909Spgoyette 142a60b9909Spgoyette #include <uvm/uvm_extern.h> 143a60b9909Spgoyette 144a60b9909Spgoyette #include <machine/reg.h> 145a60b9909Spgoyette 146d2ef544dSchristos #ifdef PTRACE_DEBUG 147a60b9909Spgoyette # define DPRINTF(a) uprintf a 14834fd0d8aSchristos static const char *pt_strings[] = { PT_STRINGS }; 149a60b9909Spgoyette #else 150a60b9909Spgoyette # define DPRINTF(a) 151a60b9909Spgoyette #endif 152a60b9909Spgoyette 153a60b9909Spgoyette static kauth_listener_t ptrace_listener; 154a60b9909Spgoyette static int process_auxv_offset(struct proc *, struct uio *); 155a60b9909Spgoyette 15671c21268Skamil extern int user_va0_disable; 15771c21268Skamil 158a60b9909Spgoyette #if 0 159a60b9909Spgoyette static int ptrace_cbref; 160a60b9909Spgoyette static kmutex_t ptrace_mtx; 161a60b9909Spgoyette static kcondvar_t ptrace_cv; 162a60b9909Spgoyette #endif 163a60b9909Spgoyette 16428f60f0eSchristos #ifdef PT_GETREGS 16528f60f0eSchristos # define case_PT_GETREGS case PT_GETREGS: 16628f60f0eSchristos #else 16728f60f0eSchristos # define case_PT_GETREGS 16828f60f0eSchristos #endif 16928f60f0eSchristos 17028f60f0eSchristos #ifdef PT_SETREGS 17128f60f0eSchristos # define case_PT_SETREGS case PT_SETREGS: 17228f60f0eSchristos #else 17328f60f0eSchristos # define case_PT_SETREGS 17428f60f0eSchristos #endif 17528f60f0eSchristos 17628f60f0eSchristos #ifdef PT_GETFPREGS 17728f60f0eSchristos # define case_PT_GETFPREGS case PT_GETFPREGS: 17828f60f0eSchristos #else 17928f60f0eSchristos # define case_PT_GETFPREGS 18028f60f0eSchristos #endif 18128f60f0eSchristos 18228f60f0eSchristos #ifdef PT_SETFPREGS 18328f60f0eSchristos # define case_PT_SETFPREGS case PT_SETFPREGS: 18428f60f0eSchristos #else 18528f60f0eSchristos # define case_PT_SETFPREGS 18628f60f0eSchristos #endif 18728f60f0eSchristos 18828f60f0eSchristos #ifdef PT_GETDBREGS 18928f60f0eSchristos # define case_PT_GETDBREGS case PT_GETDBREGS: 19028f60f0eSchristos #else 19128f60f0eSchristos # define case_PT_GETDBREGS 19228f60f0eSchristos #endif 19328f60f0eSchristos 19428f60f0eSchristos #ifdef PT_SETDBREGS 19528f60f0eSchristos # define case_PT_SETDBREGS case PT_SETDBREGS: 19628f60f0eSchristos #else 19728f60f0eSchristos # define case_PT_SETDBREGS 19828f60f0eSchristos #endif 19928f60f0eSchristos 200a60b9909Spgoyette static int 201a60b9909Spgoyette ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, 202a60b9909Spgoyette void *arg0, void *arg1, void *arg2, void *arg3) 203a60b9909Spgoyette { 204a60b9909Spgoyette struct proc *p; 205a60b9909Spgoyette int result; 206615c430aSkamil #ifdef PT_SETDBREGS 207615c430aSkamil extern int user_set_dbregs; 208615c430aSkamil #endif 209a60b9909Spgoyette 210a60b9909Spgoyette result = KAUTH_RESULT_DEFER; 211a60b9909Spgoyette p = arg0; 212a60b9909Spgoyette 213a60b9909Spgoyette #if 0 214a60b9909Spgoyette mutex_enter(&ptrace_mtx); 215a60b9909Spgoyette ptrace_cbref++; 216a60b9909Spgoyette mutex_exit(&ptrace_mtx); 217a60b9909Spgoyette #endif 218a60b9909Spgoyette if (action != KAUTH_PROCESS_PTRACE) 219a60b9909Spgoyette goto out; 220a60b9909Spgoyette 221a60b9909Spgoyette switch ((u_long)arg1) { 222615c430aSkamil #ifdef PT_SETDBREGS 223615c430aSkamil case_PT_SETDBREGS 224615c430aSkamil if (kauth_cred_getuid(cred) != 0 && user_set_dbregs == 0) { 225615c430aSkamil result = KAUTH_RESULT_DENY; 226615c430aSkamil break; 227615c430aSkamil } 228615c430aSkamil #endif 229fbffadb9Smrg /* FALLTHROUGH */ 230a60b9909Spgoyette case PT_TRACE_ME: 231a60b9909Spgoyette case PT_ATTACH: 232a60b9909Spgoyette case PT_WRITE_I: 233a60b9909Spgoyette case PT_WRITE_D: 234a60b9909Spgoyette case PT_READ_I: 235a60b9909Spgoyette case PT_READ_D: 236a60b9909Spgoyette case PT_IO: 23728f60f0eSchristos case_PT_GETREGS 23828f60f0eSchristos case_PT_SETREGS 23928f60f0eSchristos case_PT_GETFPREGS 24028f60f0eSchristos case_PT_SETFPREGS 24128f60f0eSchristos case_PT_GETDBREGS 242a60b9909Spgoyette case PT_SET_EVENT_MASK: 243a60b9909Spgoyette case PT_GET_EVENT_MASK: 244a60b9909Spgoyette case PT_GET_PROCESS_STATE: 245e4281b20Skamil case PT_SET_SIGINFO: 246e4281b20Skamil case PT_GET_SIGINFO: 247a60b9909Spgoyette #ifdef __HAVE_PTRACE_MACHDEP 248a60b9909Spgoyette PTRACE_MACHDEP_REQUEST_CASES 249a60b9909Spgoyette #endif 250a60b9909Spgoyette if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) || 251a60b9909Spgoyette ISSET(p->p_flag, PK_SUGID)) { 252a60b9909Spgoyette break; 253a60b9909Spgoyette } 254a60b9909Spgoyette 255a60b9909Spgoyette result = KAUTH_RESULT_ALLOW; 256a60b9909Spgoyette 257a60b9909Spgoyette break; 258a60b9909Spgoyette 259a60b9909Spgoyette #ifdef PT_STEP 260a60b9909Spgoyette case PT_STEP: 26105ffc73cSkamil case PT_SETSTEP: 26205ffc73cSkamil case PT_CLEARSTEP: 263a60b9909Spgoyette #endif 264a60b9909Spgoyette case PT_CONTINUE: 265a60b9909Spgoyette case PT_KILL: 266a60b9909Spgoyette case PT_DETACH: 267a60b9909Spgoyette case PT_LWPINFO: 268a60b9909Spgoyette case PT_SYSCALL: 269a60b9909Spgoyette case PT_SYSCALLEMU: 270a60b9909Spgoyette case PT_DUMPCORE: 271f9b2093dSkamil case PT_RESUME: 272f9b2093dSkamil case PT_SUSPEND: 2732e7e73e2Skamil case PT_STOP: 2744f79a484Skamil case PT_LWPSTATUS: 2754f79a484Skamil case PT_LWPNEXT: 27648b46cedSkamil case PT_SET_SIGPASS: 27748b46cedSkamil case PT_GET_SIGPASS: 278a60b9909Spgoyette result = KAUTH_RESULT_ALLOW; 279a60b9909Spgoyette break; 280a60b9909Spgoyette 281a60b9909Spgoyette default: 282a60b9909Spgoyette break; 283a60b9909Spgoyette } 284a60b9909Spgoyette 285a60b9909Spgoyette out: 286a60b9909Spgoyette #if 0 287a60b9909Spgoyette mutex_enter(&ptrace_mtx); 288a60b9909Spgoyette if (--ptrace_cbref == 0) 289a60b9909Spgoyette cv_broadcast(&ptrace_cv); 290a60b9909Spgoyette mutex_exit(&ptrace_mtx); 291a60b9909Spgoyette #endif 292a60b9909Spgoyette 293a60b9909Spgoyette return result; 294a60b9909Spgoyette } 295a60b9909Spgoyette 2962b32abf1Schristos static struct proc * 2972b32abf1Schristos ptrace_find(struct lwp *l, int req, pid_t pid) 298a60b9909Spgoyette { 2992b32abf1Schristos struct proc *t; 300a60b9909Spgoyette 301a60b9909Spgoyette /* "A foolish consistency..." XXX */ 302a60b9909Spgoyette if (req == PT_TRACE_ME) { 3032b32abf1Schristos t = l->l_proc; 304a60b9909Spgoyette mutex_enter(t->p_lock); 3052b32abf1Schristos return t; 3062b32abf1Schristos } 3072b32abf1Schristos 308a60b9909Spgoyette /* Find the process we're supposed to be operating on. */ 309a60b9909Spgoyette t = proc_find(pid); 3102b32abf1Schristos if (t == NULL) 3112b32abf1Schristos return NULL; 312a60b9909Spgoyette 313a60b9909Spgoyette /* XXX-elad */ 314a60b9909Spgoyette mutex_enter(t->p_lock); 3152b32abf1Schristos int error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, 316a60b9909Spgoyette t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL); 317a60b9909Spgoyette if (error) { 318a60b9909Spgoyette mutex_exit(t->p_lock); 3192b32abf1Schristos return NULL; 320a60b9909Spgoyette } 3212b32abf1Schristos return t; 322a60b9909Spgoyette } 323a60b9909Spgoyette 3242b32abf1Schristos static int 325e4c2eafeSmaxv ptrace_allowed(struct lwp *l, int req, struct proc *t, struct proc *p, 326e4c2eafeSmaxv bool *locked) 3272b32abf1Schristos { 328e4c2eafeSmaxv *locked = false; 329e4c2eafeSmaxv 330a60b9909Spgoyette /* 331a60b9909Spgoyette * Grab a reference on the process to prevent it from execing or 332a60b9909Spgoyette * exiting. 333a60b9909Spgoyette */ 3342b32abf1Schristos if (!rw_tryenter(&t->p_reflock, RW_READER)) 335a60b9909Spgoyette return EBUSY; 336a60b9909Spgoyette 337e4c2eafeSmaxv *locked = true; 338e4c2eafeSmaxv 339a60b9909Spgoyette /* Make sure we can operate on it. */ 340a60b9909Spgoyette switch (req) { 341a60b9909Spgoyette case PT_TRACE_ME: 3423e684ebdSkamil /* 3433e684ebdSkamil * You can't say to the parent of a process to start tracing if: 3443e684ebdSkamil * (1) the parent is initproc, 3453e684ebdSkamil */ 3463e684ebdSkamil if (p->p_pptr == initproc) 3473e684ebdSkamil return EPERM; 3483e684ebdSkamil 3493e684ebdSkamil /* 350b9541a3aSkamil * (2) the process is initproc, or 351b9541a3aSkamil */ 352b9541a3aSkamil if (p == initproc) 353b9541a3aSkamil return EPERM; 354b9541a3aSkamil 355b9541a3aSkamil /* 356b9541a3aSkamil * (3) the child is already traced. 3573e684ebdSkamil */ 3583e684ebdSkamil if (ISSET(p->p_slflag, PSL_TRACED)) 3593e684ebdSkamil return EBUSY; 3603e684ebdSkamil 3612b32abf1Schristos return 0; 362a60b9909Spgoyette 363a60b9909Spgoyette case PT_ATTACH: 364a60b9909Spgoyette /* 365a60b9909Spgoyette * You can't attach to a process if: 366a60b9909Spgoyette * (1) it's the process that's doing the attaching, 367a60b9909Spgoyette */ 368edd69790Skamil if (t == p) 3692b32abf1Schristos return EINVAL; 370a60b9909Spgoyette 371a60b9909Spgoyette /* 372b9541a3aSkamil * (2) it's a system process, 373a60b9909Spgoyette */ 3742b32abf1Schristos if (t->p_flag & PK_SYSTEM) 3752b32abf1Schristos return EPERM; 376a60b9909Spgoyette 377a60b9909Spgoyette /* 378b9541a3aSkamil * (3) the tracer is initproc, 379b9541a3aSkamil */ 380b9541a3aSkamil if (p == initproc) 381b9541a3aSkamil return EPERM; 382b9541a3aSkamil 383b9541a3aSkamil /* 384be7413daSkamil * (4) it's already being traced, 385a60b9909Spgoyette */ 3862b32abf1Schristos if (ISSET(t->p_slflag, PSL_TRACED)) 3872b32abf1Schristos return EBUSY; 388a60b9909Spgoyette 389a60b9909Spgoyette /* 390be7413daSkamil * (5) it's a vfork(2)ed parent of the current process, or 391be7413daSkamil */ 392be7413daSkamil if (ISSET(p->p_lflag, PL_PPWAIT) && p->p_pptr == t) 393be7413daSkamil return EPERM; 394be7413daSkamil 395be7413daSkamil /* 396be7413daSkamil * (6) the tracer is chrooted, and its root directory is 397a60b9909Spgoyette * not at or above the root directory of the tracee 398a60b9909Spgoyette */ 399a60b9909Spgoyette mutex_exit(t->p_lock); /* XXXSMP */ 4002b32abf1Schristos int tmp = proc_isunder(t, l); 401a60b9909Spgoyette mutex_enter(t->p_lock); /* XXXSMP */ 4022b32abf1Schristos if (!tmp) 4032b32abf1Schristos return EPERM; 4042b32abf1Schristos return 0; 405a60b9909Spgoyette 406a60b9909Spgoyette case PT_READ_I: 407a60b9909Spgoyette case PT_READ_D: 408a60b9909Spgoyette case PT_WRITE_I: 409a60b9909Spgoyette case PT_WRITE_D: 410a60b9909Spgoyette case PT_IO: 4119a6383f0Skamil case PT_SET_SIGINFO: 4129a6383f0Skamil case PT_GET_SIGINFO: 41328f60f0eSchristos case_PT_GETREGS 41428f60f0eSchristos case_PT_SETREGS 41528f60f0eSchristos case_PT_GETFPREGS 41628f60f0eSchristos case_PT_SETFPREGS 41728f60f0eSchristos case_PT_GETDBREGS 41828f60f0eSchristos case_PT_SETDBREGS 419a60b9909Spgoyette #ifdef __HAVE_PTRACE_MACHDEP 420a60b9909Spgoyette PTRACE_MACHDEP_REQUEST_CASES 421a60b9909Spgoyette #endif 422a60b9909Spgoyette /* 423a60b9909Spgoyette * You can't read/write the memory or registers of a process 424a60b9909Spgoyette * if the tracer is chrooted, and its root directory is not at 425a60b9909Spgoyette * or above the root directory of the tracee. 426a60b9909Spgoyette */ 427a60b9909Spgoyette mutex_exit(t->p_lock); /* XXXSMP */ 428a60b9909Spgoyette tmp = proc_isunder(t, l); 429a60b9909Spgoyette mutex_enter(t->p_lock); /* XXXSMP */ 4302b32abf1Schristos if (!tmp) 4312b32abf1Schristos return EPERM; 432a60b9909Spgoyette /*FALLTHROUGH*/ 433a60b9909Spgoyette 434a60b9909Spgoyette case PT_CONTINUE: 435a60b9909Spgoyette case PT_KILL: 436a60b9909Spgoyette case PT_DETACH: 437a60b9909Spgoyette case PT_LWPINFO: 438a60b9909Spgoyette case PT_SYSCALL: 439a60b9909Spgoyette case PT_SYSCALLEMU: 440a60b9909Spgoyette case PT_DUMPCORE: 441a60b9909Spgoyette #ifdef PT_STEP 442a60b9909Spgoyette case PT_STEP: 44305ffc73cSkamil case PT_SETSTEP: 44405ffc73cSkamil case PT_CLEARSTEP: 445a60b9909Spgoyette #endif 446a60b9909Spgoyette case PT_SET_EVENT_MASK: 447a60b9909Spgoyette case PT_GET_EVENT_MASK: 448a60b9909Spgoyette case PT_GET_PROCESS_STATE: 449f9b2093dSkamil case PT_RESUME: 450f9b2093dSkamil case PT_SUSPEND: 4512e7e73e2Skamil case PT_STOP: 4524f79a484Skamil case PT_LWPSTATUS: 4534f79a484Skamil case PT_LWPNEXT: 45448b46cedSkamil case PT_SET_SIGPASS: 45548b46cedSkamil case PT_GET_SIGPASS: 456a60b9909Spgoyette /* 457a60b9909Spgoyette * You can't do what you want to the process if: 458a60b9909Spgoyette * (1) It's not being traced at all, 459a60b9909Spgoyette */ 4602b32abf1Schristos if (!ISSET(t->p_slflag, PSL_TRACED)) 4612b32abf1Schristos return EPERM; 462a60b9909Spgoyette 463a60b9909Spgoyette /* 464a69b333eSkamil * (2) it's not being traced by _you_, or 465a60b9909Spgoyette */ 466a60b9909Spgoyette if (t->p_pptr != p) { 467a60b9909Spgoyette DPRINTF(("parent %d != %d\n", t->p_pptr->p_pid, 468a60b9909Spgoyette p->p_pid)); 4692b32abf1Schristos return EBUSY; 470a60b9909Spgoyette } 471a60b9909Spgoyette 472a60b9909Spgoyette /* 473a69b333eSkamil * (3) it's not currently stopped. 4742e7e73e2Skamil * 4752e7e73e2Skamil * As an exception allow PT_KILL and PT_STOP here. 476a60b9909Spgoyette */ 4772e7e73e2Skamil if (req != PT_KILL && req != PT_STOP && 4782e7e73e2Skamil (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */)) { 479a60b9909Spgoyette DPRINTF(("stat %d flag %d\n", t->p_stat, 480a60b9909Spgoyette !t->p_waited)); 4812b32abf1Schristos return EBUSY; 482a60b9909Spgoyette } 4832b32abf1Schristos return 0; 484a60b9909Spgoyette 485a60b9909Spgoyette default: /* It was not a legal request. */ 4862b32abf1Schristos return EINVAL; 4872b32abf1Schristos } 488a60b9909Spgoyette } 489a60b9909Spgoyette 4902b32abf1Schristos static int 4912b32abf1Schristos ptrace_needs_hold(int req) 4922b32abf1Schristos { 493a60b9909Spgoyette switch (req) { 494a60b9909Spgoyette #ifdef PT_STEP 495a60b9909Spgoyette case PT_STEP: 496a60b9909Spgoyette #endif 497a60b9909Spgoyette case PT_CONTINUE: 498a60b9909Spgoyette case PT_DETACH: 499a60b9909Spgoyette case PT_KILL: 500a60b9909Spgoyette case PT_SYSCALL: 501a60b9909Spgoyette case PT_SYSCALLEMU: 502a60b9909Spgoyette case PT_ATTACH: 503a60b9909Spgoyette case PT_TRACE_ME: 5042b32abf1Schristos case PT_GET_SIGINFO: 5052b32abf1Schristos case PT_SET_SIGINFO: 5062e7e73e2Skamil case PT_STOP: 5072b32abf1Schristos return 1; 508a60b9909Spgoyette default: 5092b32abf1Schristos return 0; 5102b32abf1Schristos } 5112b32abf1Schristos } 5122b32abf1Schristos 5132b32abf1Schristos static int 514f818d5c4Schristos ptrace_get_siginfo(struct proc *t, struct ptrace_methods *ptm, void *addr, 515f818d5c4Schristos size_t data) 5162b32abf1Schristos { 5172b32abf1Schristos struct ptrace_siginfo psi; 5182b32abf1Schristos 5192e300bd3Smaxv memset(&psi, 0, sizeof(psi)); 5202b32abf1Schristos psi.psi_siginfo._info = t->p_sigctx.ps_info; 5212b32abf1Schristos psi.psi_lwpid = t->p_sigctx.ps_lwp; 522d2ef544dSchristos DPRINTF(("%s: lwp=%d signal=%d\n", __func__, psi.psi_lwpid, 523d2ef544dSchristos psi.psi_siginfo.si_signo)); 5242b32abf1Schristos 525f818d5c4Schristos return ptm->ptm_copyout_siginfo(&psi, addr, data); 5262b32abf1Schristos } 5272b32abf1Schristos 5282b32abf1Schristos static int 529f818d5c4Schristos ptrace_set_siginfo(struct proc *t, struct lwp **lt, struct ptrace_methods *ptm, 530f818d5c4Schristos void *addr, size_t data) 5312b32abf1Schristos { 5322b32abf1Schristos struct ptrace_siginfo psi; 5332b32abf1Schristos 534f818d5c4Schristos int error = ptm->ptm_copyin_siginfo(&psi, addr, data); 5352b32abf1Schristos if (error) 5362b32abf1Schristos return error; 5372b32abf1Schristos 5382b32abf1Schristos /* Check that the data is a valid signal number or zero. */ 5392b32abf1Schristos if (psi.psi_siginfo.si_signo < 0 || psi.psi_siginfo.si_signo >= NSIG) 5402b32abf1Schristos return EINVAL; 5412b32abf1Schristos 5422b32abf1Schristos t->p_sigctx.ps_faked = true; 5432b32abf1Schristos t->p_sigctx.ps_info = psi.psi_siginfo._info; 5442b32abf1Schristos t->p_sigctx.ps_lwp = psi.psi_lwpid; 545d2ef544dSchristos DPRINTF(("%s: lwp=%d signal=%d\n", __func__, psi.psi_lwpid, 546d2ef544dSchristos psi.psi_siginfo.si_signo)); 5472b32abf1Schristos return 0; 5482b32abf1Schristos } 5492b32abf1Schristos 5502b32abf1Schristos static int 55148b46cedSkamil ptrace_get_sigpass(struct proc *t, void *addr, size_t data) 55248b46cedSkamil { 55348b46cedSkamil sigset_t set; 55448b46cedSkamil 55548b46cedSkamil if (data > sizeof(set) || data <= 0) { 55648b46cedSkamil DPRINTF(("%s: invalid data: %zu < %zu <= 0\n", 55748b46cedSkamil __func__, sizeof(set), data)); 55848b46cedSkamil return EINVAL; 55948b46cedSkamil } 56048b46cedSkamil 56148b46cedSkamil set = t->p_sigctx.ps_sigpass; 56248b46cedSkamil 56348b46cedSkamil return copyout(&set, addr, data); 56448b46cedSkamil } 56548b46cedSkamil 56648b46cedSkamil static int 56748b46cedSkamil ptrace_set_sigpass(struct proc *t, void *addr, size_t data) 56848b46cedSkamil { 56948b46cedSkamil sigset_t set; 57048b46cedSkamil int error; 57148b46cedSkamil 57248b46cedSkamil if (data > sizeof(set) || data <= 0) { 57348b46cedSkamil DPRINTF(("%s: invalid data: %zu < %zu <= 0\n", 57448b46cedSkamil __func__, sizeof(set), data)); 57548b46cedSkamil return EINVAL; 57648b46cedSkamil } 57748b46cedSkamil 57848b46cedSkamil memset(&set, 0, sizeof(set)); 57948b46cedSkamil 58048b46cedSkamil if ((error = copyin(addr, &set, data))) 58148b46cedSkamil return error; 58248b46cedSkamil 58348b46cedSkamil /* We catch SIGSTOP and cannot intercept SIGKILL. */ 58448b46cedSkamil sigminusset(&sigcantmask, &set); 58548b46cedSkamil 58648b46cedSkamil t->p_sigctx.ps_sigpass = set; 58748b46cedSkamil 58848b46cedSkamil return 0; 58948b46cedSkamil } 59048b46cedSkamil 59148b46cedSkamil static int 5922b32abf1Schristos ptrace_get_event_mask(struct proc *t, void *addr, size_t data) 5932b32abf1Schristos { 5942b32abf1Schristos struct ptrace_event pe; 5952b32abf1Schristos 5962b32abf1Schristos if (data != sizeof(pe)) { 5972b32abf1Schristos DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(pe))); 5982b32abf1Schristos return EINVAL; 5992b32abf1Schristos } 6002b32abf1Schristos memset(&pe, 0, sizeof(pe)); 6012b32abf1Schristos pe.pe_set_event = ISSET(t->p_slflag, PSL_TRACEFORK) ? 6022b32abf1Schristos PTRACE_FORK : 0; 6032b32abf1Schristos pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEVFORK) ? 6042b32abf1Schristos PTRACE_VFORK : 0; 6052b32abf1Schristos pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEVFORK_DONE) ? 6062b32abf1Schristos PTRACE_VFORK_DONE : 0; 6072b32abf1Schristos pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_CREATE) ? 6082b32abf1Schristos PTRACE_LWP_CREATE : 0; 6092b32abf1Schristos pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_EXIT) ? 6102b32abf1Schristos PTRACE_LWP_EXIT : 0; 6114c91c5e8Skamil pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEPOSIX_SPAWN) ? 6124c91c5e8Skamil PTRACE_POSIX_SPAWN : 0; 613d2ef544dSchristos DPRINTF(("%s: lwp=%d event=%#x\n", __func__, 614d2ef544dSchristos t->p_sigctx.ps_lwp, pe.pe_set_event)); 6152b32abf1Schristos return copyout(&pe, addr, sizeof(pe)); 6162b32abf1Schristos } 6172b32abf1Schristos 6182b32abf1Schristos static int 6192b32abf1Schristos ptrace_set_event_mask(struct proc *t, void *addr, size_t data) 6202b32abf1Schristos { 6212b32abf1Schristos struct ptrace_event pe; 6222b32abf1Schristos int error; 6232b32abf1Schristos 6242b32abf1Schristos if (data != sizeof(pe)) { 6252b32abf1Schristos DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(pe))); 6262b32abf1Schristos return EINVAL; 6272b32abf1Schristos } 6282b32abf1Schristos if ((error = copyin(addr, &pe, sizeof(pe))) != 0) 6292b32abf1Schristos return error; 6302b32abf1Schristos 631d2ef544dSchristos DPRINTF(("%s: lwp=%d event=%#x\n", __func__, 632d2ef544dSchristos t->p_sigctx.ps_lwp, pe.pe_set_event)); 6332b32abf1Schristos if (pe.pe_set_event & PTRACE_FORK) 6342b32abf1Schristos SET(t->p_slflag, PSL_TRACEFORK); 6352b32abf1Schristos else 6362b32abf1Schristos CLR(t->p_slflag, PSL_TRACEFORK); 637385d9c89Skamil 6382b32abf1Schristos if (pe.pe_set_event & PTRACE_VFORK) 6392b32abf1Schristos SET(t->p_slflag, PSL_TRACEVFORK); 6402b32abf1Schristos else 6412b32abf1Schristos CLR(t->p_slflag, PSL_TRACEVFORK); 642385d9c89Skamil 6432b32abf1Schristos if (pe.pe_set_event & PTRACE_VFORK_DONE) 6442b32abf1Schristos SET(t->p_slflag, PSL_TRACEVFORK_DONE); 6452b32abf1Schristos else 6462b32abf1Schristos CLR(t->p_slflag, PSL_TRACEVFORK_DONE); 647385d9c89Skamil 6482b32abf1Schristos if (pe.pe_set_event & PTRACE_LWP_CREATE) 6492b32abf1Schristos SET(t->p_slflag, PSL_TRACELWP_CREATE); 6502b32abf1Schristos else 6512b32abf1Schristos CLR(t->p_slflag, PSL_TRACELWP_CREATE); 652385d9c89Skamil 6532b32abf1Schristos if (pe.pe_set_event & PTRACE_LWP_EXIT) 6542b32abf1Schristos SET(t->p_slflag, PSL_TRACELWP_EXIT); 6552b32abf1Schristos else 6562b32abf1Schristos CLR(t->p_slflag, PSL_TRACELWP_EXIT); 6574c91c5e8Skamil 6584c91c5e8Skamil if (pe.pe_set_event & PTRACE_POSIX_SPAWN) 6594c91c5e8Skamil SET(t->p_slflag, PSL_TRACEPOSIX_SPAWN); 6604c91c5e8Skamil else 6614c91c5e8Skamil CLR(t->p_slflag, PSL_TRACEPOSIX_SPAWN); 6624c91c5e8Skamil 6632b32abf1Schristos return 0; 6642b32abf1Schristos } 6652b32abf1Schristos 6662b32abf1Schristos static int 6672b32abf1Schristos ptrace_get_process_state(struct proc *t, void *addr, size_t data) 6682b32abf1Schristos { 669c1b81814Skamil struct _ksiginfo *si; 6702b32abf1Schristos struct ptrace_state ps; 6712b32abf1Schristos 6722b32abf1Schristos if (data != sizeof(ps)) { 6732b32abf1Schristos DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(ps))); 6742b32abf1Schristos return EINVAL; 6752b32abf1Schristos } 6762b32abf1Schristos 6775e4bbc49Skamil if (t->p_sigctx.ps_info._signo != SIGTRAP || 6785e4bbc49Skamil (t->p_sigctx.ps_info._code != TRAP_CHLD && 6795e4bbc49Skamil t->p_sigctx.ps_info._code != TRAP_LWP)) { 680c1b81814Skamil memset(&ps, 0, sizeof(ps)); 681c1b81814Skamil } else { 682c1b81814Skamil si = &t->p_sigctx.ps_info; 68396755fb8Skamil 68496755fb8Skamil KASSERT(si->_reason._ptrace_state._pe_report_event > 0); 68596755fb8Skamil KASSERT(si->_reason._ptrace_state._option._pe_other_pid > 0); 68696755fb8Skamil 687c1b81814Skamil ps.pe_report_event = si->_reason._ptrace_state._pe_report_event; 6885e4bbc49Skamil 6895e4bbc49Skamil CTASSERT(sizeof(ps.pe_other_pid) == sizeof(ps.pe_lwp)); 6905e4bbc49Skamil ps.pe_other_pid = 691c1b81814Skamil si->_reason._ptrace_state._option._pe_other_pid; 692c1b81814Skamil } 6935e4bbc49Skamil 694d2ef544dSchristos DPRINTF(("%s: lwp=%d event=%#x pid=%d lwp=%d\n", __func__, 695d2ef544dSchristos t->p_sigctx.ps_lwp, ps.pe_report_event, 696d2ef544dSchristos ps.pe_other_pid, ps.pe_lwp)); 6972b32abf1Schristos return copyout(&ps, addr, sizeof(ps)); 6982b32abf1Schristos } 6992b32abf1Schristos 7002b32abf1Schristos static int 7012b32abf1Schristos ptrace_lwpinfo(struct proc *t, struct lwp **lt, void *addr, size_t data) 7022b32abf1Schristos { 7032b32abf1Schristos struct ptrace_lwpinfo pl; 7042b32abf1Schristos 7052b32abf1Schristos if (data != sizeof(pl)) { 7062b32abf1Schristos DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(pl))); 7072b32abf1Schristos return EINVAL; 7082b32abf1Schristos } 7092b32abf1Schristos int error = copyin(addr, &pl, sizeof(pl)); 7102b32abf1Schristos if (error) 7112b32abf1Schristos return error; 7122b32abf1Schristos 7132b32abf1Schristos lwpid_t tmp = pl.pl_lwpid; 7142b32abf1Schristos lwp_delref(*lt); 7152b32abf1Schristos mutex_enter(t->p_lock); 7162b32abf1Schristos if (tmp == 0) 7172b32abf1Schristos *lt = lwp_find_first(t); 7182b32abf1Schristos else { 7192b32abf1Schristos *lt = lwp_find(t, tmp); 7202b32abf1Schristos if (*lt == NULL) { 7212b32abf1Schristos mutex_exit(t->p_lock); 7222b32abf1Schristos return ESRCH; 7232b32abf1Schristos } 7242b32abf1Schristos *lt = LIST_NEXT(*lt, l_sibling); 7252b32abf1Schristos } 7262b32abf1Schristos 727bd8a92f7Skamil while (*lt != NULL && (!lwp_alive(*lt) || 728bd8a92f7Skamil ((*lt)->l_flag & LW_SYSTEM) != 0)) 7292b32abf1Schristos *lt = LIST_NEXT(*lt, l_sibling); 7302b32abf1Schristos 7312b32abf1Schristos pl.pl_lwpid = 0; 7322b32abf1Schristos pl.pl_event = 0; 7332b32abf1Schristos if (*lt) { 7342b32abf1Schristos lwp_addref(*lt); 7352b32abf1Schristos pl.pl_lwpid = (*lt)->l_lid; 7362b32abf1Schristos 7372b32abf1Schristos if ((*lt)->l_flag & LW_WSUSPEND) 7382b32abf1Schristos pl.pl_event = PL_EVENT_SUSPENDED; 7392b32abf1Schristos /* 7402b32abf1Schristos * If we match the lwp, or it was sent to every lwp, 7412b32abf1Schristos * we set PL_EVENT_SIGNAL. 7422b32abf1Schristos * XXX: ps_lwp == 0 means everyone and noone, so 7432b32abf1Schristos * check ps_signo too. 7442b32abf1Schristos */ 7452b32abf1Schristos else if ((*lt)->l_lid == t->p_sigctx.ps_lwp 7462b32abf1Schristos || (t->p_sigctx.ps_lwp == 0 && 747d2ef544dSchristos t->p_sigctx.ps_info._signo)) { 748d2ef544dSchristos DPRINTF(("%s: lwp=%d siglwp=%d signo %d\n", __func__, 749d2ef544dSchristos pl.pl_lwpid, t->p_sigctx.ps_lwp, 750d2ef544dSchristos t->p_sigctx.ps_info._signo)); 7512b32abf1Schristos pl.pl_event = PL_EVENT_SIGNAL; 7522b32abf1Schristos } 753d2ef544dSchristos } 7542b32abf1Schristos mutex_exit(t->p_lock); 755d2ef544dSchristos DPRINTF(("%s: lwp=%d event=%#x\n", __func__, 756d2ef544dSchristos pl.pl_lwpid, pl.pl_event)); 7572b32abf1Schristos 7582b32abf1Schristos return copyout(&pl, addr, sizeof(pl)); 7592b32abf1Schristos } 7602b32abf1Schristos 7614f79a484Skamil static int 7624f79a484Skamil ptrace_lwpstatus(struct proc *t, struct ptrace_methods *ptm, struct lwp **lt, 7634f79a484Skamil void *addr, size_t data, bool next) 7644f79a484Skamil { 7654f79a484Skamil struct ptrace_lwpstatus pls; 7664f79a484Skamil struct lwp *l; 7674f79a484Skamil int error; 7684f79a484Skamil 7694f79a484Skamil if (data > sizeof(pls) || data < sizeof(lwpid_t)) { 7704f79a484Skamil DPRINTF(("%s: invalid data: %zu < %zu < %zu\n", 7714f79a484Skamil __func__, sizeof(lwpid_t), data, sizeof(pls))); 7724f79a484Skamil return EINVAL; 7734f79a484Skamil } 77499c26a8aSmaxv error = copyin(addr, &pls.pl_lwpid, sizeof(lwpid_t)); 7754f79a484Skamil if (error) 7764f79a484Skamil return error; 7774f79a484Skamil 7784f79a484Skamil if (next) { 7794f79a484Skamil lwp_delref(*lt); 7804f79a484Skamil lwpid_t tmp = pls.pl_lwpid; 7814f79a484Skamil mutex_enter(t->p_lock); 7824f79a484Skamil if (tmp == 0) 7834f79a484Skamil *lt = lwp_find_first(t); 7844f79a484Skamil else { 7854f79a484Skamil *lt = lwp_find(t, tmp); 7864f79a484Skamil if (*lt == NULL) { 7874f79a484Skamil mutex_exit(t->p_lock); 7884f79a484Skamil return ESRCH; 7894f79a484Skamil } 7904f79a484Skamil *lt = LIST_NEXT(*lt, l_sibling); 7914f79a484Skamil } 7924f79a484Skamil 793bd8a92f7Skamil while (*lt != NULL && (!lwp_alive(*lt) || 794bd8a92f7Skamil ((*lt)->l_flag & LW_SYSTEM) != 0)) 7954f79a484Skamil *lt = LIST_NEXT(*lt, l_sibling); 7964f79a484Skamil 7974f79a484Skamil if (*lt == NULL) { 7984f79a484Skamil memset(&pls, 0, sizeof(pls)); 7994f79a484Skamil mutex_exit(t->p_lock); 8004f79a484Skamil goto out; 8014f79a484Skamil } 8024f79a484Skamil lwp_addref(*lt); 8034f79a484Skamil mutex_exit(t->p_lock); 8044f79a484Skamil 8054f79a484Skamil pls.pl_lwpid = (*lt)->l_lid; 8064f79a484Skamil } else { 8074f79a484Skamil if ((error = ptrace_update_lwp(t, lt, pls.pl_lwpid)) != 0) 8084f79a484Skamil return error; 8094f79a484Skamil } 8104f79a484Skamil 8114f79a484Skamil l = *lt; 8124f79a484Skamil 8134f79a484Skamil ptrace_read_lwpstatus(l, &pls); 8144f79a484Skamil 8154f79a484Skamil out: 81634fd0d8aSchristos DPRINTF(("%s: lwp=%d sigpend=%02x%02x%02x%02x " 81734fd0d8aSchristos "sigmask=%02x%02x%02x%02x name='%s' private=%p\n", 81834fd0d8aSchristos __func__, pls.pl_lwpid, 8194f79a484Skamil pls.pl_sigpend.__bits[0], pls.pl_sigpend.__bits[1], 8204f79a484Skamil pls.pl_sigpend.__bits[2], pls.pl_sigpend.__bits[3], 8214f79a484Skamil pls.pl_sigmask.__bits[0], pls.pl_sigmask.__bits[1], 8224f79a484Skamil pls.pl_sigmask.__bits[2], pls.pl_sigmask.__bits[3], 8234f79a484Skamil pls.pl_name, pls.pl_private)); 8244f79a484Skamil 8254f79a484Skamil return ptm->ptm_copyout_lwpstatus(&pls, addr, data); 8264f79a484Skamil } 8274f79a484Skamil 8282b32abf1Schristos static int 8292b32abf1Schristos ptrace_startstop(struct proc *t, struct lwp **lt, int rq, void *addr, 8302b32abf1Schristos size_t data) 8312b32abf1Schristos { 8322b32abf1Schristos int error; 8332b32abf1Schristos 8342b32abf1Schristos if ((error = ptrace_update_lwp(t, lt, data)) != 0) 8352b32abf1Schristos return error; 8362b32abf1Schristos 837d2ef544dSchristos DPRINTF(("%s: lwp=%d request=%d\n", __func__, (*lt)->l_lid, rq)); 8382b32abf1Schristos lwp_lock(*lt); 8392b32abf1Schristos if (rq == PT_SUSPEND) 840a35a4fe3Skamil (*lt)->l_flag |= LW_DBGSUSPEND; 841a35a4fe3Skamil else { 842a35a4fe3Skamil (*lt)->l_flag &= ~LW_DBGSUSPEND; 843a35a4fe3Skamil if ((*lt)->l_flag != LSSUSPENDED) 844a35a4fe3Skamil (*lt)->l_stat = LSSTOP; 845a35a4fe3Skamil } 8462b32abf1Schristos lwp_unlock(*lt); 8472b32abf1Schristos return 0; 8482b32abf1Schristos } 8492b32abf1Schristos 85028f60f0eSchristos #ifdef PT_REGISTERS 8512b32abf1Schristos static int 8522b32abf1Schristos ptrace_uio_dir(int req) 8532b32abf1Schristos { 8542b32abf1Schristos switch (req) { 85528f60f0eSchristos case_PT_GETREGS 85628f60f0eSchristos case_PT_GETFPREGS 85728f60f0eSchristos case_PT_GETDBREGS 8582b32abf1Schristos return UIO_READ; 85928f60f0eSchristos case_PT_SETREGS 86028f60f0eSchristos case_PT_SETFPREGS 86128f60f0eSchristos case_PT_SETDBREGS 8622b32abf1Schristos return UIO_WRITE; 8632b32abf1Schristos default: 8642b32abf1Schristos return -1; 8652b32abf1Schristos } 8662b32abf1Schristos } 8672b32abf1Schristos 8682b32abf1Schristos static int 8692b32abf1Schristos ptrace_regs(struct lwp *l, struct lwp **lt, int rq, struct ptrace_methods *ptm, 8702b32abf1Schristos void *addr, size_t data) 8712b32abf1Schristos { 8722b32abf1Schristos int error; 8736df93363Srin struct proc *p, *t; 8742b32abf1Schristos struct vmspace *vm; 8752b32abf1Schristos 8766df93363Srin p = l->l_proc; /* tracer */ 8776df93363Srin t = (*lt)->l_proc; /* traced */ 8786df93363Srin 8792b32abf1Schristos if ((error = ptrace_update_lwp(t, lt, data)) != 0) 8802b32abf1Schristos return error; 8812b32abf1Schristos 8822b32abf1Schristos int dir = ptrace_uio_dir(rq); 8832b32abf1Schristos size_t size; 8842b32abf1Schristos int (*func)(struct lwp *, struct lwp *, struct uio *); 8852b32abf1Schristos 886d2ef544dSchristos DPRINTF(("%s: lwp=%d request=%d\n", __func__, l->l_lid, rq)); 887d2ef544dSchristos 8882b32abf1Schristos switch (rq) { 889*5b38d912Schristos #if defined(PT_REGS) 89028f60f0eSchristos case_PT_GETREGS 89128f60f0eSchristos case_PT_SETREGS 8922b32abf1Schristos if (!process_validregs(*lt)) 8932b32abf1Schristos return EINVAL; 8946df93363Srin size = PROC_REGSZ(p); 8952b32abf1Schristos func = ptm->ptm_doregs; 896a60b9909Spgoyette break; 8972b32abf1Schristos #endif 898*5b38d912Schristos #if defined(PT_FPREGS) 89928f60f0eSchristos case_PT_GETFPREGS 90028f60f0eSchristos case_PT_SETFPREGS 9012b32abf1Schristos if (!process_validfpregs(*lt)) 9022b32abf1Schristos return EINVAL; 9036df93363Srin size = PROC_FPREGSZ(p); 9042b32abf1Schristos func = ptm->ptm_dofpregs; 9052b32abf1Schristos break; 9062b32abf1Schristos #endif 907*5b38d912Schristos #if defined(PT_DBREGS) 90828f60f0eSchristos case_PT_GETDBREGS 90928f60f0eSchristos case_PT_SETDBREGS 9102b32abf1Schristos if (!process_validdbregs(*lt)) 9112b32abf1Schristos return EINVAL; 9126df93363Srin size = PROC_DBREGSZ(p); 9132b32abf1Schristos func = ptm->ptm_dodbregs; 9142b32abf1Schristos break; 9152b32abf1Schristos #endif 9162b32abf1Schristos default: 9172b32abf1Schristos return EINVAL; 9182b32abf1Schristos } 9192b32abf1Schristos 920bac82b91Schristos error = proc_vmspace_getref(l->l_proc, &vm); 9212b32abf1Schristos if (error) 9222b32abf1Schristos return error; 9232b32abf1Schristos 9242b32abf1Schristos struct uio uio; 9252b32abf1Schristos struct iovec iov; 9262b32abf1Schristos 9272b32abf1Schristos iov.iov_base = addr; 9282b32abf1Schristos iov.iov_len = size; 9292b32abf1Schristos uio.uio_iov = &iov; 9302b32abf1Schristos uio.uio_iovcnt = 1; 9312b32abf1Schristos uio.uio_offset = 0; 9322b32abf1Schristos uio.uio_resid = iov.iov_len; 9332b32abf1Schristos uio.uio_rw = dir; 9342b32abf1Schristos uio.uio_vmspace = vm; 9352b32abf1Schristos 9362b32abf1Schristos error = (*func)(l, *lt, &uio); 9372b32abf1Schristos uvmspace_free(vm); 9382b32abf1Schristos return error; 9392b32abf1Schristos } 94028f60f0eSchristos #endif 94128f60f0eSchristos 94228f60f0eSchristos static int 9432e7e73e2Skamil ptrace_sendsig(struct lwp *l, int req, struct proc *t, struct lwp *lt, int signo, int resume_all) 94428f60f0eSchristos { 94528f60f0eSchristos ksiginfo_t ksi; 94628f60f0eSchristos 94728f60f0eSchristos /* Finally, deliver the requested signal (or none). */ 94828f60f0eSchristos if (t->p_stat == SSTOP) { 94928f60f0eSchristos /* 95028f60f0eSchristos * Unstop the process. If it needs to take a 95128f60f0eSchristos * signal, make all efforts to ensure that at 95228f60f0eSchristos * an LWP runs to see it. 95328f60f0eSchristos */ 95428f60f0eSchristos t->p_xsig = signo; 9557f2cb72eSkamil 9567f2cb72eSkamil /* 95720c051d7Skamil * signo > 0 check prevents a potential panic, as 9587f2cb72eSkamil * sigismember(&...,0) is invalid check and signo 9597f2cb72eSkamil * can be equal to 0 as a special case of no-signal. 9607f2cb72eSkamil */ 9617f2cb72eSkamil if (signo > 0 && sigismember(&stopsigmask, signo)) { 9627f2cb72eSkamil t->p_waited = 0; 9637f2cb72eSkamil child_psignal(t, 0); 9647f2cb72eSkamil } else if (resume_all) 96528f60f0eSchristos proc_unstop(t); 96628f60f0eSchristos else 96728f60f0eSchristos lwp_unstop(lt); 9685e50d45eSchristos 96941f5d30eSchristos if (req != PT_KILL || signo != SIGKILL) 97028f60f0eSchristos return 0; 97128f60f0eSchristos } 97228f60f0eSchristos 9732e7e73e2Skamil KASSERT(req == PT_KILL || req == PT_STOP || req == PT_ATTACH); 97428f60f0eSchristos 9752e7e73e2Skamil KSI_INIT(&ksi); 9762e7e73e2Skamil ksi.ksi_signo = signo; 9772e7e73e2Skamil ksi.ksi_code = SI_USER; 9782e7e73e2Skamil ksi.ksi_pid = l->l_proc->p_pid; 9792e7e73e2Skamil ksi.ksi_uid = kauth_cred_geteuid(l->l_cred); 9802e7e73e2Skamil 9812e7e73e2Skamil t->p_sigctx.ps_faked = false; 9822e7e73e2Skamil 9832e7e73e2Skamil DPRINTF(("%s: pid=%d.%d signal=%d resume_all=%d\n", __func__, t->p_pid, 9842e7e73e2Skamil lt->l_lid, signo, resume_all)); 9852e7e73e2Skamil 9862e7e73e2Skamil return kpsignal2(t, &ksi); 98728f60f0eSchristos } 98828f60f0eSchristos 98928f60f0eSchristos static int 99028f60f0eSchristos ptrace_dumpcore(struct lwp *lt, char *path, size_t len) 99128f60f0eSchristos { 99228f60f0eSchristos int error; 99328f60f0eSchristos if (path != NULL) { 99428f60f0eSchristos 99528f60f0eSchristos if (len >= MAXPATHLEN) 99628f60f0eSchristos return EINVAL; 99728f60f0eSchristos 99828f60f0eSchristos char *src = path; 99928f60f0eSchristos path = kmem_alloc(len + 1, KM_SLEEP); 100028f60f0eSchristos error = copyin(src, path, len); 100128f60f0eSchristos if (error) 100228f60f0eSchristos goto out; 100328f60f0eSchristos path[len] = '\0'; 100428f60f0eSchristos } 1005d2ef544dSchristos DPRINTF(("%s: lwp=%d\n", __func__, lt->l_lid)); 100686069f28Spgoyette MODULE_HOOK_CALL(coredump_hook, (lt, path), 0, error); 100728f60f0eSchristos out: 100828f60f0eSchristos if (path) 100928f60f0eSchristos kmem_free(path, len + 1); 101028f60f0eSchristos return error; 101128f60f0eSchristos } 101228f60f0eSchristos 101328f60f0eSchristos static int 101428f60f0eSchristos ptrace_doio(struct lwp *l, struct proc *t, struct lwp *lt, 1015d3ef0ca6Schristos struct ptrace_io_desc *piod, void *addr, bool sysspace) 101628f60f0eSchristos { 101728f60f0eSchristos struct uio uio; 101828f60f0eSchristos struct iovec iov; 101928f60f0eSchristos int error, tmp; 102028f60f0eSchristos 102128f60f0eSchristos error = 0; 102228f60f0eSchristos iov.iov_base = piod->piod_addr; 102328f60f0eSchristos iov.iov_len = piod->piod_len; 102428f60f0eSchristos uio.uio_iov = &iov; 102528f60f0eSchristos uio.uio_iovcnt = 1; 102628f60f0eSchristos uio.uio_offset = (off_t)(unsigned long)piod->piod_offs; 102728f60f0eSchristos uio.uio_resid = piod->piod_len; 102828f60f0eSchristos 1029d2ef544dSchristos DPRINTF(("%s: lwp=%d request=%d\n", __func__, l->l_lid, piod->piod_op)); 1030d2ef544dSchristos 103128f60f0eSchristos switch (piod->piod_op) { 103228f60f0eSchristos case PIOD_READ_D: 103328f60f0eSchristos case PIOD_READ_I: 103428f60f0eSchristos uio.uio_rw = UIO_READ; 103528f60f0eSchristos break; 103628f60f0eSchristos case PIOD_WRITE_D: 103728f60f0eSchristos case PIOD_WRITE_I: 103828f60f0eSchristos /* 103928f60f0eSchristos * Can't write to a RAS 104028f60f0eSchristos */ 104128f60f0eSchristos if (ras_lookup(t, addr) != (void *)-1) { 104228f60f0eSchristos return EACCES; 104328f60f0eSchristos } 104428f60f0eSchristos uio.uio_rw = UIO_WRITE; 104528f60f0eSchristos break; 104628f60f0eSchristos case PIOD_READ_AUXV: 104728f60f0eSchristos uio.uio_rw = UIO_READ; 104828f60f0eSchristos tmp = t->p_execsw->es_arglen; 104928f60f0eSchristos if (uio.uio_offset > tmp) 105028f60f0eSchristos return EIO; 105128f60f0eSchristos if (uio.uio_resid > tmp - uio.uio_offset) 105228f60f0eSchristos uio.uio_resid = tmp - uio.uio_offset; 105328f60f0eSchristos piod->piod_len = iov.iov_len = uio.uio_resid; 105428f60f0eSchristos error = process_auxv_offset(t, &uio); 105528f60f0eSchristos break; 105628f60f0eSchristos default: 105728f60f0eSchristos error = EINVAL; 105828f60f0eSchristos break; 105928f60f0eSchristos } 1060d3ef0ca6Schristos 106128f60f0eSchristos if (error) 106228f60f0eSchristos return error; 106328f60f0eSchristos 1064d3ef0ca6Schristos if (sysspace) { 1065d3ef0ca6Schristos uio.uio_vmspace = vmspace_kernel(); 1066d3ef0ca6Schristos } else { 1067d3ef0ca6Schristos error = proc_vmspace_getref(l->l_proc, &uio.uio_vmspace); 1068d3ef0ca6Schristos if (error) 106928f60f0eSchristos return error; 107028f60f0eSchristos } 1071d3ef0ca6Schristos 1072d3ef0ca6Schristos error = process_domem(l, lt, &uio); 1073d3ef0ca6Schristos if (!sysspace) 1074d3ef0ca6Schristos uvmspace_free(uio.uio_vmspace); 1075d3ef0ca6Schristos if (error) 1076d3ef0ca6Schristos return error; 107728f60f0eSchristos piod->piod_len -= uio.uio_resid; 107828f60f0eSchristos return 0; 107928f60f0eSchristos } 10802b32abf1Schristos 10812b32abf1Schristos int 10822b32abf1Schristos do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid, 10832b32abf1Schristos void *addr, int data, register_t *retval) 10842b32abf1Schristos { 10852b32abf1Schristos struct proc *p = l->l_proc; 10862b32abf1Schristos struct lwp *lt = NULL; 10872b32abf1Schristos struct lwp *lt2; 10882b32abf1Schristos struct proc *t; /* target process */ 10892b32abf1Schristos struct ptrace_io_desc piod; 10902b32abf1Schristos int error, write, tmp, pheld; 10912b32abf1Schristos int signo = 0; 10922b32abf1Schristos int resume_all; 1093e4c2eafeSmaxv bool locked; 10942b32abf1Schristos error = 0; 10952b32abf1Schristos 109634fd0d8aSchristos DPRINTF(("%s: tracer=%d tracee=%d req=%s(%d) addr=%p data=%d\n", 109734fd0d8aSchristos __func__, p->p_pid, pid, 109834fd0d8aSchristos (u_int)req < __arraycount(pt_strings) ? pt_strings[req] : "???", 109934fd0d8aSchristos req, addr, data)); 11002b32abf1Schristos /* 11012b32abf1Schristos * If attaching or detaching, we need to get a write hold on the 11022b32abf1Schristos * proclist lock so that we can re-parent the target process. 11032b32abf1Schristos */ 11040eaaa024Sad mutex_enter(&proc_lock); 11052b32abf1Schristos 11062b32abf1Schristos t = ptrace_find(l, req, pid); 11072b32abf1Schristos if (t == NULL) { 11080eaaa024Sad mutex_exit(&proc_lock); 11092b32abf1Schristos return ESRCH; 11102b32abf1Schristos } 11112b32abf1Schristos 11122b32abf1Schristos pheld = 1; 1113e4c2eafeSmaxv if ((error = ptrace_allowed(l, req, t, p, &locked)) != 0) 11142b32abf1Schristos goto out; 11152b32abf1Schristos 11162b32abf1Schristos if ((error = kauth_authorize_process(l->l_cred, 11172b32abf1Schristos KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req), NULL, NULL)) != 0) 11182b32abf1Schristos goto out; 11192b32abf1Schristos 11202b32abf1Schristos if ((lt = lwp_find_first(t)) == NULL) { 11212b32abf1Schristos error = ESRCH; 11222b32abf1Schristos goto out; 11232b32abf1Schristos } 11242b32abf1Schristos 11252b32abf1Schristos /* Do single-step fixup if needed. */ 11262b32abf1Schristos FIX_SSTEP(t); 11272b32abf1Schristos KASSERT(lt != NULL); 11282b32abf1Schristos lwp_addref(lt); 11292b32abf1Schristos 11302b32abf1Schristos /* 11312b32abf1Schristos * Which locks do we need held? XXX Ugly. 11322b32abf1Schristos */ 11332b32abf1Schristos if ((pheld = ptrace_needs_hold(req)) == 0) { 11342b32abf1Schristos mutex_exit(t->p_lock); 11350eaaa024Sad mutex_exit(&proc_lock); 1136a60b9909Spgoyette } 1137a60b9909Spgoyette 1138a60b9909Spgoyette /* Now do the operation. */ 1139a60b9909Spgoyette write = 0; 1140a60b9909Spgoyette *retval = 0; 1141a60b9909Spgoyette tmp = 0; 1142a60b9909Spgoyette resume_all = 1; 1143a60b9909Spgoyette 1144a60b9909Spgoyette switch (req) { 1145a60b9909Spgoyette case PT_TRACE_ME: 1146a60b9909Spgoyette /* Just set the trace flag. */ 1147a60b9909Spgoyette SET(t->p_slflag, PSL_TRACED); 1148a60b9909Spgoyette t->p_opptr = t->p_pptr; 1149a60b9909Spgoyette break; 1150a60b9909Spgoyette 11518f414e64Skamil /* 11528f414e64Skamil * The I and D separate address space has been inherited from PDP-11. 11538f414e64Skamil * The 16-bit UNIX started with a single address space per program, 11548f414e64Skamil * but was extended to two 16-bit (2 x 64kb) address spaces. 11558f414e64Skamil * 11568f414e64Skamil * We no longer maintain this feature in maintained architectures, but 11576584ea56Sandvar * we keep the API for backward compatibility. Currently the I and D 11588f414e64Skamil * operations are exactly the same and not distinguished in debuggers. 11598f414e64Skamil */ 11608f414e64Skamil case PT_WRITE_I: 1161a60b9909Spgoyette case PT_WRITE_D: 1162a60b9909Spgoyette write = 1; 1163a60b9909Spgoyette tmp = data; 1164a60b9909Spgoyette /* FALLTHROUGH */ 11658f414e64Skamil case PT_READ_I: 1166a60b9909Spgoyette case PT_READ_D: 1167d3ef0ca6Schristos piod.piod_addr = &tmp; 1168d3ef0ca6Schristos piod.piod_len = sizeof(tmp); 1169d3ef0ca6Schristos piod.piod_offs = addr; 1170d3ef0ca6Schristos piod.piod_op = write ? PIOD_WRITE_D : PIOD_READ_D; 1171d3ef0ca6Schristos if ((error = ptrace_doio(l, t, lt, &piod, addr, true)) != 0) 1172d3ef0ca6Schristos break; 117371c21268Skamil /* 117471c21268Skamil * For legacy reasons we treat here two results as success: 117571c21268Skamil * - incomplete transfer piod.piod_len < sizeof(tmp) 117671c21268Skamil * - no transfer piod.piod_len == 0 117771c21268Skamil * 117871c21268Skamil * This means that there is no way to determine whether 117971c21268Skamil * transfer operation was performed in PT_WRITE and PT_READ 118071c21268Skamil * calls. 118171c21268Skamil */ 1182a60b9909Spgoyette if (!write) 1183a60b9909Spgoyette *retval = tmp; 1184a60b9909Spgoyette break; 1185a60b9909Spgoyette 1186a60b9909Spgoyette case PT_IO: 1187f818d5c4Schristos if ((error = ptm->ptm_copyin_piod(&piod, addr, data)) != 0) 1188a60b9909Spgoyette break; 1189c3c12ae2Skamil if (piod.piod_len < 1) { 1190c3c12ae2Skamil error = EINVAL; 1191c3c12ae2Skamil break; 1192c3c12ae2Skamil } 1193d3ef0ca6Schristos if ((error = ptrace_doio(l, t, lt, &piod, addr, false)) != 0) 1194a60b9909Spgoyette break; 119571c21268Skamil /* 119671c21268Skamil * For legacy reasons we treat here two results as success: 119771c21268Skamil * - incomplete transfer piod.piod_len < sizeof(tmp) 119871c21268Skamil * - no transfer piod.piod_len == 0 119971c21268Skamil */ 1200a0a9a3b4Schristos error = ptm->ptm_copyout_piod(&piod, addr, data); 1201a60b9909Spgoyette break; 1202a60b9909Spgoyette 1203a60b9909Spgoyette case PT_DUMPCORE: 120428f60f0eSchristos error = ptrace_dumpcore(lt, addr, data); 1205a60b9909Spgoyette break; 1206a60b9909Spgoyette 1207a60b9909Spgoyette #ifdef PT_STEP 1208a60b9909Spgoyette case PT_STEP: 1209a60b9909Spgoyette /* 1210a60b9909Spgoyette * From the 4.4BSD PRM: 1211a60b9909Spgoyette * "Execution continues as in request PT_CONTINUE; however 1212a60b9909Spgoyette * as soon as possible after execution of at least one 1213a60b9909Spgoyette * instruction, execution stops again. [ ... ]" 1214a60b9909Spgoyette */ 1215a60b9909Spgoyette #endif 1216a60b9909Spgoyette case PT_CONTINUE: 1217a60b9909Spgoyette case PT_SYSCALL: 1218a60b9909Spgoyette case PT_DETACH: 1219a60b9909Spgoyette if (req == PT_SYSCALL) { 1220a60b9909Spgoyette if (!ISSET(t->p_slflag, PSL_SYSCALL)) { 1221a60b9909Spgoyette SET(t->p_slflag, PSL_SYSCALL); 1222a60b9909Spgoyette #ifdef __HAVE_SYSCALL_INTERN 1223a60b9909Spgoyette (*t->p_emul->e_syscall_intern)(t); 1224a60b9909Spgoyette #endif 1225a60b9909Spgoyette } 1226a60b9909Spgoyette } else { 1227a60b9909Spgoyette if (ISSET(t->p_slflag, PSL_SYSCALL)) { 1228a60b9909Spgoyette CLR(t->p_slflag, PSL_SYSCALL); 1229a60b9909Spgoyette #ifdef __HAVE_SYSCALL_INTERN 1230a60b9909Spgoyette (*t->p_emul->e_syscall_intern)(t); 1231a60b9909Spgoyette #endif 1232a60b9909Spgoyette } 1233a60b9909Spgoyette } 1234a60b9909Spgoyette t->p_trace_enabled = trace_is_enabled(t); 1235a60b9909Spgoyette 1236a60b9909Spgoyette /* 1237a60b9909Spgoyette * Pick up the LWPID, if supplied. There are two cases: 1238a60b9909Spgoyette * data < 0 : step or continue single thread, lwp = -data 1239a60b9909Spgoyette * data > 0 in PT_STEP : step this thread, continue others 1240a60b9909Spgoyette * For operations other than PT_STEP, data > 0 means 1241a60b9909Spgoyette * data is the signo to deliver to the process. 1242a60b9909Spgoyette */ 1243a60b9909Spgoyette tmp = data; 1244a60b9909Spgoyette if (tmp >= 0) { 1245a60b9909Spgoyette #ifdef PT_STEP 1246a60b9909Spgoyette if (req == PT_STEP) 1247a60b9909Spgoyette signo = 0; 1248a60b9909Spgoyette else 1249a60b9909Spgoyette #endif 1250a60b9909Spgoyette { 1251a60b9909Spgoyette signo = tmp; 1252a60b9909Spgoyette tmp = 0; /* don't search for LWP */ 1253a60b9909Spgoyette } 1254c18c9a67Skamil } else if (tmp == INT_MIN) { 1255c18c9a67Skamil error = ESRCH; 1256c18c9a67Skamil break; 1257c18c9a67Skamil } else { 1258a60b9909Spgoyette tmp = -tmp; 1259c18c9a67Skamil } 1260a60b9909Spgoyette 1261a60b9909Spgoyette if (tmp > 0) { 1262a60b9909Spgoyette if (req == PT_DETACH) { 1263a60b9909Spgoyette error = EINVAL; 1264a60b9909Spgoyette break; 1265a60b9909Spgoyette } 1266a60b9909Spgoyette lwp_delref2 (lt); 1267a60b9909Spgoyette lt = lwp_find(t, tmp); 1268a60b9909Spgoyette if (lt == NULL) { 1269a60b9909Spgoyette error = ESRCH; 1270a60b9909Spgoyette break; 1271a60b9909Spgoyette } 1272a60b9909Spgoyette lwp_addref(lt); 1273a60b9909Spgoyette resume_all = 0; 1274a60b9909Spgoyette signo = 0; 1275a60b9909Spgoyette } 1276a60b9909Spgoyette 1277a60b9909Spgoyette /* 1278a60b9909Spgoyette * From the 4.4BSD PRM: 1279a60b9909Spgoyette * "The data argument is taken as a signal number and the 1280a60b9909Spgoyette * child's execution continues at location addr as if it 1281a60b9909Spgoyette * incurred that signal. Normally the signal number will 1282a60b9909Spgoyette * be either 0 to indicate that the signal that caused the 1283a60b9909Spgoyette * stop should be ignored, or that value fetched out of 1284a60b9909Spgoyette * the process's image indicating which signal caused 1285a60b9909Spgoyette * the stop. If addr is (int *)1 then execution continues 1286a60b9909Spgoyette * from where it stopped." 1287a60b9909Spgoyette */ 1288a60b9909Spgoyette 1289a60b9909Spgoyette /* Check that the data is a valid signal number or zero. */ 1290a60b9909Spgoyette if (signo < 0 || signo >= NSIG) { 1291a60b9909Spgoyette error = EINVAL; 1292a60b9909Spgoyette break; 1293a60b9909Spgoyette } 1294a60b9909Spgoyette 1295f9b2093dSkamil /* Prevent process deadlock */ 1296f9b2093dSkamil if (resume_all) { 1297f9b2093dSkamil #ifdef PT_STEP 1298f9b2093dSkamil if (req == PT_STEP) { 1299a35a4fe3Skamil if (lt->l_flag & 1300a35a4fe3Skamil (LW_WSUSPEND | LW_DBGSUSPEND)) { 1301f9b2093dSkamil error = EDEADLK; 1302f9b2093dSkamil break; 1303f9b2093dSkamil } 1304f9b2093dSkamil } else 1305f9b2093dSkamil #endif 1306f9b2093dSkamil { 1307f9b2093dSkamil error = EDEADLK; 1308f9b2093dSkamil LIST_FOREACH(lt2, &t->p_lwps, l_sibling) { 1309a35a4fe3Skamil if ((lt2->l_flag & 1310a35a4fe3Skamil (LW_WSUSPEND | LW_DBGSUSPEND)) == 0 1311a35a4fe3Skamil ) { 1312f9b2093dSkamil error = 0; 1313f9b2093dSkamil break; 1314f9b2093dSkamil } 1315f9b2093dSkamil } 1316f9b2093dSkamil if (error != 0) 1317f9b2093dSkamil break; 1318f9b2093dSkamil } 1319f9b2093dSkamil } else { 132060274cddSkamil if (lt->l_flag & (LW_WSUSPEND | LW_DBGSUSPEND)) { 1321f9b2093dSkamil error = EDEADLK; 1322f9b2093dSkamil break; 1323f9b2093dSkamil } 1324f9b2093dSkamil } 1325f9b2093dSkamil 1326ff3a41b3Skamil /* 1327815185c6Skamil * Reject setting program counter to 0x0 if VA0 is disabled. 1328ff3a41b3Skamil * 132971c21268Skamil * Not all kernels implement this feature to set Program 133071c21268Skamil * Counter in one go in PT_CONTINUE and similar operations. 133171c21268Skamil * This causes portability issues as passing address 0x0 133271c21268Skamil * on these kernels is no-operation, but can cause failure 133371c21268Skamil * in most cases on NetBSD. 1334ff3a41b3Skamil */ 133571c21268Skamil if (user_va0_disable && addr == 0) { 1336ff3a41b3Skamil error = EINVAL; 1337ff3a41b3Skamil break; 1338ff3a41b3Skamil } 1339ff3a41b3Skamil 1340a60b9909Spgoyette /* If the address parameter is not (int *)1, set the pc. */ 1341a60b9909Spgoyette if ((int *)addr != (int *)1) { 1342a60b9909Spgoyette error = process_set_pc(lt, addr); 1343a60b9909Spgoyette if (error != 0) 1344a60b9909Spgoyette break; 1345a60b9909Spgoyette } 1346a60b9909Spgoyette #ifdef PT_STEP 1347a60b9909Spgoyette /* 1348a60b9909Spgoyette * Arrange for a single-step, if that's requested and possible. 1349a60b9909Spgoyette * More precisely, set the single step status as requested for 1350a60b9909Spgoyette * the requested thread, and clear it for other threads. 1351a60b9909Spgoyette */ 1352a60b9909Spgoyette LIST_FOREACH(lt2, &t->p_lwps, l_sibling) { 13530b0d79c7Skamil error = process_sstep(lt2, 13540b0d79c7Skamil ISSET(lt2->l_pflag, LP_SINGLESTEP)); 13550b0d79c7Skamil if (error) 13560b0d79c7Skamil break; 1357a60b9909Spgoyette } 13580b0d79c7Skamil if (error) 13590b0d79c7Skamil break; 136005ffc73cSkamil error = process_sstep(lt, 136105ffc73cSkamil ISSET(lt->l_pflag, LP_SINGLESTEP) || req == PT_STEP); 1362a60b9909Spgoyette if (error) 1363a60b9909Spgoyette break; 1364a60b9909Spgoyette #endif 1365a60b9909Spgoyette if (req == PT_DETACH) { 13660d3a6b1dSkamil CLR(t->p_slflag, 13670d3a6b1dSkamil PSL_TRACED|PSL_TRACEDCHILD|PSL_SYSCALL); 1368a60b9909Spgoyette 136948b46cedSkamil /* clear sigpass mask */ 137048b46cedSkamil sigemptyset(&t->p_sigctx.ps_sigpass); 137148b46cedSkamil 1372a60b9909Spgoyette /* give process back to original parent or init */ 1373a60b9909Spgoyette if (t->p_opptr != t->p_pptr) { 1374a60b9909Spgoyette struct proc *pp = t->p_opptr; 1375a60b9909Spgoyette proc_reparent(t, pp ? pp : initproc); 1376a60b9909Spgoyette } 1377a60b9909Spgoyette 1378a60b9909Spgoyette /* not being traced any more */ 1379a60b9909Spgoyette t->p_opptr = NULL; 138005ffc73cSkamil 138105ffc73cSkamil /* clear single step */ 138205ffc73cSkamil LIST_FOREACH(lt2, &t->p_lwps, l_sibling) { 138305ffc73cSkamil CLR(lt2->l_pflag, LP_SINGLESTEP); 138405ffc73cSkamil } 138505ffc73cSkamil CLR(lt->l_pflag, LP_SINGLESTEP); 1386a60b9909Spgoyette } 1387a60b9909Spgoyette sendsig: 13882e7e73e2Skamil error = ptrace_sendsig(l, req, t, lt, signo, resume_all); 1389a60b9909Spgoyette break; 1390a60b9909Spgoyette 1391a60b9909Spgoyette case PT_SYSCALLEMU: 1392a60b9909Spgoyette if (!ISSET(t->p_slflag, PSL_SYSCALL) || t->p_stat != SSTOP) { 1393a60b9909Spgoyette error = EINVAL; 1394a60b9909Spgoyette break; 1395a60b9909Spgoyette } 1396a60b9909Spgoyette SET(t->p_slflag, PSL_SYSCALLEMU); 1397a60b9909Spgoyette break; 1398a60b9909Spgoyette 139905ffc73cSkamil #ifdef PT_STEP 140005ffc73cSkamil case PT_SETSTEP: 140105ffc73cSkamil write = 1; 140205ffc73cSkamil 1403fbffadb9Smrg /* FALLTHROUGH */ 140405ffc73cSkamil case PT_CLEARSTEP: 140505ffc73cSkamil /* write = 0 done above. */ 14062b32abf1Schristos if ((error = ptrace_update_lwp(t, <, data)) != 0) 140705ffc73cSkamil break; 140805ffc73cSkamil 14092b32abf1Schristos if (write) 141005ffc73cSkamil SET(lt->l_pflag, LP_SINGLESTEP); 141105ffc73cSkamil else 141205ffc73cSkamil CLR(lt->l_pflag, LP_SINGLESTEP); 141305ffc73cSkamil break; 141405ffc73cSkamil #endif 141505ffc73cSkamil 1416a60b9909Spgoyette case PT_KILL: 1417a60b9909Spgoyette /* just send the process a KILL signal. */ 1418a60b9909Spgoyette signo = SIGKILL; 1419a60b9909Spgoyette goto sendsig; /* in PT_CONTINUE, above. */ 1420a60b9909Spgoyette 14212e7e73e2Skamil case PT_STOP: 14222e7e73e2Skamil /* just send the process a STOP signal. */ 14232e7e73e2Skamil signo = SIGSTOP; 14242e7e73e2Skamil goto sendsig; /* in PT_CONTINUE, above. */ 14252e7e73e2Skamil 1426a60b9909Spgoyette case PT_ATTACH: 1427a60b9909Spgoyette /* 1428a60b9909Spgoyette * Go ahead and set the trace flag. 1429a60b9909Spgoyette * Save the old parent (it's reset in 1430a60b9909Spgoyette * _DETACH, and also in kern_exit.c:wait4() 1431a60b9909Spgoyette * Reparent the process so that the tracing 1432a60b9909Spgoyette * proc gets to see all the action. 1433a60b9909Spgoyette * Stop the target. 1434a60b9909Spgoyette */ 14359b5ab015Schristos proc_changeparent(t, p); 1436f1999451Schristos signo = SIGSTOP; 1437a60b9909Spgoyette goto sendsig; 1438a60b9909Spgoyette 1439a60b9909Spgoyette case PT_GET_EVENT_MASK: 14402b32abf1Schristos error = ptrace_get_event_mask(t, addr, data); 1441a60b9909Spgoyette break; 1442a60b9909Spgoyette 1443a60b9909Spgoyette case PT_SET_EVENT_MASK: 14442b32abf1Schristos error = ptrace_set_event_mask(t, addr, data); 1445a60b9909Spgoyette break; 1446a60b9909Spgoyette 1447a60b9909Spgoyette case PT_GET_PROCESS_STATE: 14482b32abf1Schristos error = ptrace_get_process_state(t, addr, data); 1449a60b9909Spgoyette break; 1450a60b9909Spgoyette 1451a60b9909Spgoyette case PT_LWPINFO: 14522b32abf1Schristos error = ptrace_lwpinfo(t, <, addr, data); 1453a60b9909Spgoyette break; 1454a60b9909Spgoyette 1455e4281b20Skamil case PT_SET_SIGINFO: 1456f818d5c4Schristos error = ptrace_set_siginfo(t, <, ptm, addr, data); 1457e4281b20Skamil break; 1458e4281b20Skamil 1459e4281b20Skamil case PT_GET_SIGINFO: 1460f818d5c4Schristos error = ptrace_get_siginfo(t, ptm, addr, data); 1461e4281b20Skamil break; 1462e4281b20Skamil 1463f9b2093dSkamil case PT_RESUME: 1464f9b2093dSkamil case PT_SUSPEND: 14652b32abf1Schristos error = ptrace_startstop(t, <, req, addr, data); 1466f9b2093dSkamil break; 1467f9b2093dSkamil 14684f79a484Skamil case PT_LWPSTATUS: 14694f79a484Skamil error = ptrace_lwpstatus(t, ptm, <, addr, data, false); 14704f79a484Skamil break; 14714f79a484Skamil 14724f79a484Skamil case PT_LWPNEXT: 14734f79a484Skamil error = ptrace_lwpstatus(t, ptm, <, addr, data, true); 14744f79a484Skamil break; 14754f79a484Skamil 147648b46cedSkamil case PT_SET_SIGPASS: 147748b46cedSkamil error = ptrace_set_sigpass(t, addr, data); 147848b46cedSkamil break; 147948b46cedSkamil 148048b46cedSkamil case PT_GET_SIGPASS: 148148b46cedSkamil error = ptrace_get_sigpass(t, addr, data); 148248b46cedSkamil break; 148348b46cedSkamil 148428f60f0eSchristos #ifdef PT_REGISTERS 148528f60f0eSchristos case_PT_SETREGS 148628f60f0eSchristos case_PT_GETREGS 148728f60f0eSchristos case_PT_SETFPREGS 148828f60f0eSchristos case_PT_GETFPREGS 148928f60f0eSchristos case_PT_SETDBREGS 149028f60f0eSchristos case_PT_GETDBREGS 14912b32abf1Schristos error = ptrace_regs(l, <, req, ptm, addr, data); 1492241cf91dSkamil break; 1493241cf91dSkamil #endif 1494241cf91dSkamil 1495a60b9909Spgoyette #ifdef __HAVE_PTRACE_MACHDEP 1496a60b9909Spgoyette PTRACE_MACHDEP_REQUEST_CASES 1497f4ced9b4Smgorny error = ptrace_machdep_dorequest(l, <, req, addr, data); 1498a60b9909Spgoyette break; 1499a60b9909Spgoyette #endif 1500a60b9909Spgoyette } 1501a60b9909Spgoyette 15022b32abf1Schristos out: 1503a60b9909Spgoyette if (pheld) { 1504a60b9909Spgoyette mutex_exit(t->p_lock); 15050eaaa024Sad mutex_exit(&proc_lock); 1506a60b9909Spgoyette } 1507a60b9909Spgoyette if (lt != NULL) 1508a60b9909Spgoyette lwp_delref(lt); 1509e4c2eafeSmaxv if (locked) 1510a60b9909Spgoyette rw_exit(&t->p_reflock); 1511a60b9909Spgoyette 1512a60b9909Spgoyette return error; 1513a60b9909Spgoyette } 1514a60b9909Spgoyette 1515a60b9909Spgoyette static int 1516a60b9909Spgoyette process_auxv_offset(struct proc *p, struct uio *uio) 1517a60b9909Spgoyette { 1518a60b9909Spgoyette struct ps_strings pss; 1519a60b9909Spgoyette int error; 1520a60b9909Spgoyette off_t off = (off_t)p->p_psstrp; 1521a60b9909Spgoyette 1522a60b9909Spgoyette if ((error = copyin_psstrings(p, &pss)) != 0) 1523a60b9909Spgoyette return error; 1524a60b9909Spgoyette 1525a60b9909Spgoyette if (pss.ps_envstr == NULL) 1526a60b9909Spgoyette return EIO; 1527a60b9909Spgoyette 152882833002Srin #ifdef COMPAT_NETBSD32 152982833002Srin if (p->p_flag & PK_32) 153082833002Srin uio->uio_offset += (off_t)((vaddr_t)pss.ps_envstr + 153182833002Srin sizeof(uint32_t) * (pss.ps_nenvstr + 1)); 153282833002Srin else 153382833002Srin #endif 153482833002Srin uio->uio_offset += (off_t)(vaddr_t)(pss.ps_envstr + 153582833002Srin pss.ps_nenvstr + 1); 153682833002Srin 1537a60b9909Spgoyette #ifdef __MACHINE_STACK_GROWS_UP 1538a60b9909Spgoyette if (uio->uio_offset < off) 1539a60b9909Spgoyette return EIO; 1540a60b9909Spgoyette #else 1541a60b9909Spgoyette if (uio->uio_offset > off) 1542a60b9909Spgoyette return EIO; 1543a60b9909Spgoyette if ((uio->uio_offset + uio->uio_resid) > off) 1544a60b9909Spgoyette uio->uio_resid = off - uio->uio_offset; 1545a60b9909Spgoyette #endif 1546a60b9909Spgoyette return 0; 1547a60b9909Spgoyette } 1548484b4a02Skamil 1549484b4a02Skamil MODULE(MODULE_CLASS_EXEC, ptrace_common, NULL); 1550484b4a02Skamil 1551484b4a02Skamil static int 1552355e5900Spgoyette ptrace_common_init(void) 1553355e5900Spgoyette { 1554355e5900Spgoyette 1555e78beab4Spgoyette #if 0 1556e78beab4Spgoyette mutex_init(&ptrace_mtx, MUTEX_DEFAULT, IPL_NONE); 1557e78beab4Spgoyette cv_init(&ptrace_cv, "ptracecb"); 1558e78beab4Spgoyette ptrace_cbref = 0; 1559e78beab4Spgoyette #endif 1560e78beab4Spgoyette ptrace_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS, 1561e78beab4Spgoyette ptrace_listener_cb, NULL); 1562355e5900Spgoyette return 0; 1563355e5900Spgoyette } 1564355e5900Spgoyette 1565355e5900Spgoyette static int 1566355e5900Spgoyette ptrace_common_fini(void) 1567355e5900Spgoyette { 1568355e5900Spgoyette 1569e78beab4Spgoyette kauth_unlisten_scope(ptrace_listener); 1570e78beab4Spgoyette 1571e78beab4Spgoyette #if 0 1572e78beab4Spgoyette /* Make sure no-one is executing our kauth listener */ 1573e78beab4Spgoyette 1574e78beab4Spgoyette mutex_enter(&ptrace_mtx); 1575e78beab4Spgoyette while (ptrace_cbref != 0) 1576e78beab4Spgoyette cv_wait(&ptrace_cv, &ptrace_mtx); 1577e78beab4Spgoyette mutex_exit(&ptrace_mtx); 1578e78beab4Spgoyette mutex_destroy(&ptrace_mtx); 1579e78beab4Spgoyette cv_destroy(&ptrace_cv); 1580e78beab4Spgoyette #endif 1581e78beab4Spgoyette 1582355e5900Spgoyette return 0; 1583355e5900Spgoyette } 1584355e5900Spgoyette 1585355e5900Spgoyette static int 1586484b4a02Skamil ptrace_common_modcmd(modcmd_t cmd, void *arg) 1587484b4a02Skamil { 1588484b4a02Skamil int error; 1589484b4a02Skamil 1590484b4a02Skamil switch (cmd) { 1591484b4a02Skamil case MODULE_CMD_INIT: 1592355e5900Spgoyette error = ptrace_common_init(); 1593484b4a02Skamil break; 1594484b4a02Skamil case MODULE_CMD_FINI: 1595355e5900Spgoyette error = ptrace_common_fini(); 1596484b4a02Skamil break; 1597484b4a02Skamil default: 1598484b4a02Skamil ptrace_hooks(); 1599484b4a02Skamil error = ENOTTY; 1600484b4a02Skamil break; 1601484b4a02Skamil } 1602484b4a02Skamil return error; 1603484b4a02Skamil } 1604