1 /* $NetBSD: sys_process_lwpstatus.c,v 1.3 2020/10/20 22:31:20 rin Exp $ */ 2 3 /*- 4 * Copyright (c) 2019 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.3 2020/10/20 22:31:20 rin Exp $"); 31 32 #ifdef _KERNEL_OPT 33 #include "opt_ptrace.h" 34 #include "opt_ktrace.h" 35 #include "opt_pax.h" 36 #include "opt_compat_netbsd32.h" 37 #endif 38 39 #if defined(__HAVE_COMPAT_NETBSD32) && !defined(COMPAT_NETBSD32) \ 40 && !defined(_RUMPKERNEL) 41 #define COMPAT_NETBSD32 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/errno.h> 47 #include <sys/lwp.h> 48 #include <sys/proc.h> 49 #include <sys/ptrace.h> 50 51 #ifndef PTRACE_REGS_ALIGN 52 #define PTRACE_REGS_ALIGN /* nothing */ 53 #endif 54 55 void 56 ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls) 57 { 58 59 KASSERT(l->l_lid == pls->pl_lwpid); 60 61 memcpy(&pls->pl_sigmask, &l->l_sigmask, sizeof(pls->pl_sigmask)); 62 memcpy(&pls->pl_sigpend, &l->l_sigpend.sp_set, sizeof(pls->pl_sigpend)); 63 64 if (l->l_name == NULL) 65 memset(&pls->pl_name, 0, PL_LNAMELEN); 66 else { 67 KASSERT(strlen(l->l_name) < PL_LNAMELEN); 68 strncpy(pls->pl_name, l->l_name, PL_LNAMELEN); 69 } 70 71 #ifdef PTRACE_LWP_GETPRIVATE 72 pls->pl_private = (void *)(intptr_t)PTRACE_LWP_GETPRIVATE(l); 73 #else 74 pls->pl_private = l->l_private; 75 #endif 76 } 77 78 void 79 process_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls) 80 { 81 82 pls->pl_lwpid = l->l_lid; 83 84 ptrace_read_lwpstatus(l, pls); 85 } 86 87 int 88 ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid) 89 { 90 if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1) 91 return 0; 92 93 mutex_enter(t->p_lock); 94 lwp_delref2(*lt); 95 96 *lt = lwp_find(t, lid); 97 if (*lt == NULL) { 98 mutex_exit(t->p_lock); 99 return ESRCH; 100 } 101 102 if ((*lt)->l_flag & LW_SYSTEM) { 103 mutex_exit(t->p_lock); 104 *lt = NULL; 105 return EINVAL; 106 } 107 108 lwp_addref(*lt); 109 mutex_exit(t->p_lock); 110 111 return 0; 112 } 113 114 int 115 process_validfpregs(struct lwp *l) 116 { 117 118 #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) 119 return (l->l_flag & LW_SYSTEM) == 0; 120 #else 121 return 0; 122 #endif 123 } 124 125 int 126 process_validregs(struct lwp *l) 127 { 128 129 #if defined(PT_SETREGS) || defined(PT_GETREGS) 130 return (l->l_flag & LW_SYSTEM) == 0; 131 #else 132 return 0; 133 #endif 134 } 135 136 int 137 process_validdbregs(struct lwp *l) 138 { 139 140 #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) 141 return (l->l_flag & LW_SYSTEM) == 0; 142 #else 143 return 0; 144 #endif 145 } 146 147 #ifdef PT_REGISTERS 148 static int 149 proc_regio(struct lwp *l, struct uio *uio, size_t ks, ptrace_regrfunc_t r, 150 ptrace_regwfunc_t w) 151 { 152 char buf[1024] PTRACE_REGS_ALIGN; 153 int error; 154 char *kv; 155 size_t kl; 156 157 if (ks > sizeof(buf)) 158 return E2BIG; 159 160 if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks) 161 return EINVAL; 162 163 kv = buf + uio->uio_offset; 164 kl = ks - uio->uio_offset; 165 166 if (kl > uio->uio_resid) 167 kl = uio->uio_resid; 168 169 error = (*r)(l, buf, &ks); 170 if (error == 0) 171 error = uiomove(kv, kl, uio); 172 if (error == 0 && uio->uio_rw == UIO_WRITE) { 173 if (l->l_stat != LSSTOP) 174 error = EBUSY; 175 else 176 error = (*w)(l, buf, ks); 177 } 178 179 uio->uio_offset = 0; 180 return error; 181 } 182 #endif 183 184 int 185 process_doregs(struct lwp *curl /*tracer*/, 186 struct lwp *l /*traced*/, 187 struct uio *uio) 188 { 189 #if defined(PT_GETREGS) || defined(PT_SETREGS) 190 size_t s; 191 ptrace_regrfunc_t r; 192 ptrace_regwfunc_t w; 193 194 #ifdef COMPAT_NETBSD32 195 const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; 196 197 if (__predict_false(pk32)) { 198 if ((l->l_proc->p_flag & PK_32) == 0) { 199 // 32 bit tracer can't trace 64 bit process 200 return EINVAL; 201 } 202 s = sizeof(process_reg32); 203 r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs32); 204 w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs32); 205 } else 206 #endif 207 { 208 s = sizeof(struct reg); 209 r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs); 210 w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs); 211 } 212 return proc_regio(l, uio, s, r, w); 213 #else 214 return EINVAL; 215 #endif 216 } 217 218 int 219 process_dofpregs(struct lwp *curl /*tracer*/, 220 struct lwp *l /*traced*/, 221 struct uio *uio) 222 { 223 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) 224 size_t s; 225 ptrace_regrfunc_t r; 226 ptrace_regwfunc_t w; 227 228 #ifdef COMPAT_NETBSD32 229 const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; 230 231 if (__predict_false(pk32)) { 232 if ((l->l_proc->p_flag & PK_32) == 0) { 233 // 32 bit tracer can't trace 64 bit process 234 return EINVAL; 235 } 236 s = sizeof(process_fpreg32); 237 r = (ptrace_regrfunc_t)process_read_fpregs32; 238 w = (ptrace_regwfunc_t)process_write_fpregs32; 239 } else 240 #endif 241 { 242 s = sizeof(struct fpreg); 243 r = (ptrace_regrfunc_t)process_read_fpregs; 244 w = (ptrace_regwfunc_t)process_write_fpregs; 245 } 246 return proc_regio(l, uio, s, r, w); 247 #else 248 return EINVAL; 249 #endif 250 } 251 252 253 int 254 process_dodbregs(struct lwp *curl /*tracer*/, 255 struct lwp *l /*traced*/, 256 struct uio *uio) 257 { 258 #if defined(PT_GETDBREGS) || defined(PT_SETDBREGS) 259 size_t s; 260 ptrace_regrfunc_t r; 261 ptrace_regwfunc_t w; 262 263 #ifdef COMPAT_NETBSD32 264 const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; 265 266 if (__predict_false(pk32)) { 267 if ((l->l_proc->p_flag & PK_32) == 0) { 268 // 32 bit tracer can't trace 64 bit process 269 return EINVAL; 270 } 271 s = sizeof(process_dbreg32); 272 r = (ptrace_regrfunc_t)process_read_dbregs32; 273 w = (ptrace_regwfunc_t)process_write_dbregs32; 274 } else 275 #endif 276 { 277 s = sizeof(struct dbreg); 278 r = (ptrace_regrfunc_t)process_read_dbregs; 279 w = (ptrace_regwfunc_t)process_write_dbregs; 280 } 281 return proc_regio(l, uio, s, r, w); 282 #else 283 return EINVAL; 284 #endif 285 } 286