1/* $NetBSD: netbsd32_ptrace.c,v 1.9 2021/09/07 11:43:05 riastradh Exp $ */ 2 3/* 4 * Copyright (c) 2016 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nick Hudson 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.9 2021/09/07 11:43:05 riastradh Exp $"); 34 35#if defined(_KERNEL_OPT) 36#include "opt_ptrace.h" 37#include "opt_compat_netbsd.h" 38#endif 39 40#include <sys/param.h> 41#include <sys/module.h> 42#include <sys/ptrace.h> 43#include <sys/syscallvar.h> 44 45#include <compat/netbsd32/netbsd32.h> 46#include <compat/netbsd32/netbsd32_syscall.h> 47#include <compat/netbsd32/netbsd32_syscallargs.h> 48#include <compat/netbsd32/netbsd32_conv.h> 49 50#ifndef PTRACE_TRANSLATE_REQUEST32 51#define PTRACE_TRANSLATE_REQUEST32(x) x 52#endif 53 54static void 55netbsd32_lwpstatus_to_lwpstatus32(struct netbsd32_ptrace_lwpstatus *pls32, 56 const struct ptrace_lwpstatus *pls) 57{ 58 memset(pls32, 0, sizeof(*pls32)); 59 pls32->pl_lwpid = pls->pl_lwpid; 60 pls32->pl_sigpend = pls->pl_sigpend; 61 pls32->pl_sigmask = pls->pl_sigmask; 62 memcpy(&pls32->pl_name, &pls->pl_name, PL_LNAMELEN); 63 NETBSD32PTR32(pls32->pl_private, pls->pl_private); 64} 65 66void 67netbsd32_read_lwpstatus(struct lwp *l, struct netbsd32_ptrace_lwpstatus *pls32) 68{ 69 struct ptrace_lwpstatus pls; 70 71 process_read_lwpstatus(l, &pls); 72 73 netbsd32_lwpstatus_to_lwpstatus32(pls32, &pls); 74} 75 76/* 77 * PTRACE methods 78 */ 79 80static int 81netbsd32_copyin_piod(struct ptrace_io_desc *piod, const void *addr, size_t len) 82{ 83 struct netbsd32_ptrace_io_desc piod32; 84 85 if (len != 0 && sizeof(piod32) != len) 86 return EINVAL; 87 88 int error = copyin(addr, &piod32, sizeof(piod32)); 89 if (error) 90 return error; 91 piod->piod_op = piod32.piod_op; 92 piod->piod_offs = NETBSD32PTR64(piod32.piod_offs); 93 piod->piod_addr = NETBSD32PTR64(piod32.piod_addr); 94 piod->piod_len = (size_t)piod32.piod_len; 95 96 return 0; 97} 98 99static int 100netbsd32_copyout_piod(const struct ptrace_io_desc *piod, void *addr, size_t len) 101{ 102 struct netbsd32_ptrace_io_desc piod32; 103 104 if (len != 0 && sizeof(piod32) != len) 105 return EINVAL; 106 107 memset(&piod32, 0, sizeof(piod32)); 108 piod32.piod_op = piod->piod_op; 109 NETBSD32PTR32(piod32.piod_offs, piod->piod_offs); 110 NETBSD32PTR32(piod32.piod_addr, piod->piod_addr); 111 piod32.piod_len = (netbsd32_size_t)piod->piod_len; 112 return copyout(&piod32, addr, sizeof(piod32)); 113} 114 115static int 116netbsd32_copyin_siginfo(struct ptrace_siginfo *psi, const void *addr, size_t len) 117{ 118 struct netbsd32_ptrace_siginfo psi32; 119 120 if (sizeof(psi32) != len) 121 return EINVAL; 122 123 int error = copyin(addr, &psi32, sizeof(psi32)); 124 if (error) 125 return error; 126 psi->psi_lwpid = psi32.psi_lwpid; 127 netbsd32_si32_to_si(&psi->psi_siginfo, &psi32.psi_siginfo); 128 return 0; 129} 130 131static int 132netbsd32_copyout_siginfo(const struct ptrace_siginfo *psi, void *addr, size_t len) 133{ 134 struct netbsd32_ptrace_siginfo psi32; 135 136 if (sizeof(psi32) != len) 137 return EINVAL; 138 139 memset(&psi32, 0, sizeof(psi32)); 140 psi32.psi_lwpid = psi->psi_lwpid; 141 netbsd32_si_to_si32(&psi32.psi_siginfo, &psi->psi_siginfo); 142 return copyout(&psi32, addr, sizeof(psi32)); 143} 144 145static int 146netbsd32_copyout_lwpstatus(const struct ptrace_lwpstatus *pls, void *addr, size_t len) 147{ 148 struct netbsd32_ptrace_lwpstatus pls32; 149 150 if (len > sizeof(pls32)) 151 return EINVAL; 152 153 netbsd32_lwpstatus_to_lwpstatus32(&pls32, pls); 154 155 return copyout(&pls32, addr, MIN(len, sizeof(pls32))); 156} 157 158static int 159netbsd32_doregs(struct lwp *curl /*tracer*/, 160 struct lwp *l /*traced*/, 161 struct uio *uio) 162{ 163#if defined(PT_GETREGS) || defined(PT_SETREGS) 164 process_reg32 r32; 165 int error; 166 char *kv; 167 int kl; 168 169 if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32)) 170 return EINVAL; 171 172 kl = sizeof(r32); 173 kv = (char *)&r32; 174 175 kv += uio->uio_offset; 176 kl -= uio->uio_offset; 177 if ((size_t)kl > uio->uio_resid) 178 kl = uio->uio_resid; 179 error = process_read_regs32(l, &r32); 180 if (error == 0) 181 error = uiomove(kv, kl, uio); 182 if (error == 0 && uio->uio_rw == UIO_WRITE) { 183 if (l->l_stat != LSSTOP) 184 error = EBUSY; 185 else 186 error = process_write_regs32(l, &r32); 187 } 188 189 uio->uio_offset = 0; 190 return error; 191#else 192 return EINVAL; 193#endif 194} 195 196static int 197netbsd32_dofpregs(struct lwp *curl /*tracer*/, 198 struct lwp *l /*traced*/, 199 struct uio *uio) 200{ 201#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) 202 process_fpreg32 r32; 203 int error; 204 char *kv; 205 size_t kl; 206 207 KASSERT(l->l_proc->p_flag & PK_32); 208 if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32)) 209 return EINVAL; 210 kl = sizeof(r32); 211 kv = (char *)&r32; 212 213 kv += uio->uio_offset; 214 kl -= uio->uio_offset; 215 if (kl > uio->uio_resid) 216 kl = uio->uio_resid; 217 218 error = process_read_fpregs32(l, &r32, &kl); 219 if (error == 0) 220 error = uiomove(kv, kl, uio); 221 if (error == 0 && uio->uio_rw == UIO_WRITE) { 222 if (l->l_stat != LSSTOP) 223 error = EBUSY; 224 else 225 error = process_write_fpregs32(l, &r32, kl); 226 } 227 uio->uio_offset = 0; 228 return error; 229#else 230 return EINVAL; 231#endif 232} 233 234static int 235netbsd32_dodbregs(struct lwp *curl /*tracer*/, 236 struct lwp *l /*traced*/, 237 struct uio *uio) 238{ 239#if defined(PT_GETDBREGS) || defined(PT_SETDBREGS) 240 process_dbreg32 r32; 241 int error; 242 char *kv; 243 size_t kl; 244 245 KASSERT(l->l_proc->p_flag & PK_32); 246 if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32)) 247 return EINVAL; 248 kl = sizeof(r32); 249 kv = (char *)&r32; 250 251 kv += uio->uio_offset; 252 kl -= uio->uio_offset; 253 if (kl > uio->uio_resid) 254 kl = uio->uio_resid; 255 256 error = process_read_dbregs32(l, &r32, &kl); 257 if (error == 0) 258 error = uiomove(kv, kl, uio); 259 if (error == 0 && uio->uio_rw == UIO_WRITE) { 260 if (l->l_stat != LSSTOP) 261 error = EBUSY; 262 else 263 error = process_write_dbregs32(l, &r32, kl); 264 } 265 uio->uio_offset = 0; 266 return error; 267#else 268 return EINVAL; 269#endif 270} 271 272static struct ptrace_methods netbsd32_ptm = { 273 .ptm_copyin_piod = netbsd32_copyin_piod, 274 .ptm_copyout_piod = netbsd32_copyout_piod, 275 .ptm_copyin_siginfo = netbsd32_copyin_siginfo, 276 .ptm_copyout_siginfo = netbsd32_copyout_siginfo, 277 .ptm_copyout_lwpstatus = netbsd32_copyout_lwpstatus, 278 .ptm_doregs = netbsd32_doregs, 279 .ptm_dofpregs = netbsd32_dofpregs, 280 .ptm_dodbregs = netbsd32_dodbregs 281}; 282 283 284int 285netbsd32_ptrace(struct lwp *l, const struct netbsd32_ptrace_args *uap, 286 register_t *retval) 287{ 288 int req; 289 290 /* { 291 syscallarg(int) req; 292 syscallarg(pid_t) pid; 293 syscallarg(netbsd32_voidp *) addr; 294 syscallarg(int) data; 295 } */ 296 297 req = PTRACE_TRANSLATE_REQUEST32(SCARG(uap, req)); 298 if (req == -1) 299 return EOPNOTSUPP; 300 301 return do_ptrace(&netbsd32_ptm, l, req, SCARG(uap, pid), 302 SCARG_P32(uap, addr), SCARG(uap, data), retval); 303} 304 305static const struct syscall_package compat_ptrace_syscalls[] = { 306 { NETBSD32_SYS_netbsd32_ptrace, 0, (sy_call_t *)netbsd32_ptrace }, 307 { 0, 0, NULL }, 308}; 309 310#define DEPS "compat_netbsd32,ptrace_common" 311 312MODULE(MODULE_CLASS_EXEC, compat_netbsd32_ptrace, DEPS); 313 314static int 315compat_netbsd32_ptrace_modcmd(modcmd_t cmd, void *arg) 316{ 317 int error; 318 319 switch (cmd) { 320 case MODULE_CMD_INIT: 321 error = syscall_establish(&emul_netbsd32, 322 compat_ptrace_syscalls); 323 break; 324 case MODULE_CMD_FINI: 325 error = syscall_disestablish(&emul_netbsd32, 326 compat_ptrace_syscalls); 327 break; 328 default: 329 error = ENOTTY; 330 break; 331 } 332 return error; 333} 334