1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org> 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 8 * ("CTSRD"), as part of the DARPA CRASH research programme. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #include <sys/param.h> 34 #include <sys/lock.h> 35 #include <sys/proc.h> 36 #include <sys/ptrace.h> 37 #include <sys/sx.h> 38 #include <sys/syscallsubr.h> 39 40 #include <machine/../linux/linux.h> 41 #include <machine/../linux/linux_proto.h> 42 #include <compat/linux/linux_emul.h> 43 #include <compat/linux/linux_errno.h> 44 #include <compat/linux/linux_misc.h> 45 #include <compat/linux/linux_signal.h> 46 #include <compat/linux/linux_util.h> 47 48 #define LINUX_PTRACE_TRACEME 0 49 #define LINUX_PTRACE_PEEKTEXT 1 50 #define LINUX_PTRACE_PEEKDATA 2 51 #define LINUX_PTRACE_PEEKUSER 3 52 #define LINUX_PTRACE_POKETEXT 4 53 #define LINUX_PTRACE_POKEDATA 5 54 #define LINUX_PTRACE_POKEUSER 6 55 #define LINUX_PTRACE_CONT 7 56 #define LINUX_PTRACE_KILL 8 57 #define LINUX_PTRACE_SINGLESTEP 9 58 #define LINUX_PTRACE_GETREGS 12 59 #define LINUX_PTRACE_SETREGS 13 60 #define LINUX_PTRACE_GETFPREGS 14 61 #define LINUX_PTRACE_SETFPREGS 15 62 #define LINUX_PTRACE_ATTACH 16 63 #define LINUX_PTRACE_DETACH 17 64 #define LINUX_PTRACE_SYSCALL 24 65 #define LINUX_PTRACE_SETOPTIONS 0x4200 66 #define LINUX_PTRACE_GETEVENTMSG 0x4201 67 #define LINUX_PTRACE_GETSIGINFO 0x4202 68 #define LINUX_PTRACE_GETREGSET 0x4204 69 #define LINUX_PTRACE_SEIZE 0x4206 70 #define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e 71 72 #define LINUX_PTRACE_EVENT_EXEC 4 73 #define LINUX_PTRACE_EVENT_EXIT 6 74 75 #define LINUX_PTRACE_O_TRACESYSGOOD 1 76 #define LINUX_PTRACE_O_TRACEFORK 2 77 #define LINUX_PTRACE_O_TRACEVFORK 4 78 #define LINUX_PTRACE_O_TRACECLONE 8 79 #define LINUX_PTRACE_O_TRACEEXEC 16 80 #define LINUX_PTRACE_O_TRACEVFORKDONE 32 81 #define LINUX_PTRACE_O_TRACEEXIT 64 82 #define LINUX_PTRACE_O_TRACESECCOMP 128 83 #define LINUX_PTRACE_O_EXITKILL 1048576 84 #define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152 85 86 #define LINUX_NT_PRSTATUS 0x1 87 #define LINUX_NT_PRFPREG 0x2 88 #define LINUX_NT_X86_XSTATE 0x202 89 90 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \ 91 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \ 92 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \ 93 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \ 94 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \ 95 LINUX_PTRACE_O_SUSPEND_SECCOMP) 96 97 #define LINUX_PTRACE_SYSCALL_INFO_NONE 0 98 #define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1 99 #define LINUX_PTRACE_SYSCALL_INFO_EXIT 2 100 101 static int 102 map_signum(int lsig, int *bsigp) 103 { 104 int bsig; 105 106 if (lsig == 0) { 107 *bsigp = 0; 108 return (0); 109 } 110 111 if (lsig < 0 || lsig > LINUX_SIGRTMAX) 112 return (EINVAL); 113 114 bsig = linux_to_bsd_signal(lsig); 115 if (bsig == SIGSTOP) 116 bsig = 0; 117 118 *bsigp = bsig; 119 return (0); 120 } 121 122 int 123 linux_ptrace_status(struct thread *td, pid_t pid, int status) 124 { 125 struct ptrace_lwpinfo lwpinfo; 126 struct linux_pemuldata *pem; 127 register_t saved_retval; 128 int error; 129 130 saved_retval = td->td_retval[0]; 131 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 132 td->td_retval[0] = saved_retval; 133 if (error != 0) { 134 linux_msg(td, "PT_LWPINFO failed with error %d", error); 135 return (status); 136 } 137 138 pem = pem_find(td->td_proc); 139 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); 140 141 LINUX_PEM_SLOCK(pem); 142 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && 143 lwpinfo.pl_flags & PL_FLAG_SCE) 144 status |= (LINUX_SIGTRAP | 0x80) << 8; 145 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) && 146 lwpinfo.pl_flags & PL_FLAG_SCX) { 147 if (lwpinfo.pl_flags & PL_FLAG_EXEC) 148 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8; 149 else 150 status |= (LINUX_SIGTRAP | 0x80) << 8; 151 } 152 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) && 153 lwpinfo.pl_flags & PL_FLAG_EXITED) 154 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8; 155 LINUX_PEM_SUNLOCK(pem); 156 157 return (status); 158 } 159 160 static int 161 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data) 162 { 163 int error; 164 165 error = kern_ptrace(td, PT_READ_I, pid, addr, 0); 166 if (error == 0) 167 error = copyout(td->td_retval, data, sizeof(l_int)); 168 else if (error == ENOMEM) 169 error = EIO; 170 td->td_retval[0] = error; 171 172 return (error); 173 } 174 175 static int 176 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data) 177 { 178 struct linux_pemuldata *pem; 179 int mask; 180 181 mask = 0; 182 183 if (data & ~LINUX_PTRACE_O_MASK) { 184 linux_msg(td, "unknown ptrace option %lx set; " 185 "returning EINVAL", 186 data & ~LINUX_PTRACE_O_MASK); 187 return (EINVAL); 188 } 189 190 pem = pem_find(td->td_proc); 191 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__)); 192 193 /* 194 * PTRACE_O_EXITKILL is ignored, we do that by default. 195 */ 196 197 LINUX_PEM_XLOCK(pem); 198 if (data & LINUX_PTRACE_O_TRACESYSGOOD) { 199 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD; 200 } else { 201 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD; 202 } 203 LINUX_PEM_XUNLOCK(pem); 204 205 if (data & LINUX_PTRACE_O_TRACEFORK) 206 mask |= PTRACE_FORK; 207 208 if (data & LINUX_PTRACE_O_TRACEVFORK) 209 mask |= PTRACE_VFORK; 210 211 if (data & LINUX_PTRACE_O_TRACECLONE) 212 mask |= PTRACE_VFORK; 213 214 if (data & LINUX_PTRACE_O_TRACEEXEC) 215 mask |= PTRACE_EXEC; 216 217 if (data & LINUX_PTRACE_O_TRACEVFORKDONE) 218 mask |= PTRACE_VFORK; /* XXX: Close enough? */ 219 220 if (data & LINUX_PTRACE_O_TRACEEXIT) { 221 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT; 222 } else { 223 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT; 224 } 225 226 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask))); 227 } 228 229 static int 230 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data) 231 { 232 233 linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL"); 234 return (EINVAL); 235 } 236 237 static int 238 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data) 239 { 240 struct ptrace_lwpinfo lwpinfo; 241 l_siginfo_t l_siginfo; 242 int error, sig; 243 244 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 245 if (error != 0) { 246 linux_msg(td, "PT_LWPINFO failed with error %d", error); 247 return (error); 248 } 249 250 if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) { 251 error = EINVAL; 252 linux_msg(td, "no PL_FLAG_SI, returning %d", error); 253 return (error); 254 } 255 256 sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo); 257 memset(&l_siginfo, 0, sizeof(l_siginfo)); 258 siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig); 259 error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo)); 260 return (error); 261 } 262 263 static int 264 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data) 265 { 266 struct reg b_reg; 267 struct linux_pt_regset l_regset; 268 int error; 269 270 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 271 if (error != 0) 272 return (error); 273 274 bsd_to_linux_regset(&b_reg, &l_regset); 275 error = linux_ptrace_getregs_machdep(td, pid, &l_regset); 276 if (error != 0) 277 return (error); 278 279 error = copyout(&l_regset, (void *)data, sizeof(l_regset)); 280 return (error); 281 } 282 283 static int 284 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data) 285 { 286 struct reg b_reg; 287 struct linux_pt_regset l_regset; 288 int error; 289 290 error = copyin(data, &l_regset, sizeof(l_regset)); 291 if (error != 0) 292 return (error); 293 linux_to_bsd_regset(&b_reg, &l_regset); 294 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0); 295 return (error); 296 } 297 298 static int 299 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data) 300 { 301 struct reg b_reg; 302 struct linux_pt_regset l_regset; 303 struct iovec iov; 304 size_t len; 305 int error; 306 307 error = copyin((const void *)data, &iov, sizeof(iov)); 308 if (error != 0) { 309 linux_msg(td, "copyin error %d", error); 310 return (error); 311 } 312 313 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 314 if (error != 0) 315 return (error); 316 317 bsd_to_linux_regset(&b_reg, &l_regset); 318 error = linux_ptrace_getregs_machdep(td, pid, &l_regset); 319 if (error != 0) 320 return (error); 321 322 len = MIN(iov.iov_len, sizeof(l_regset)); 323 error = copyout(&l_regset, (void *)iov.iov_base, len); 324 if (error != 0) { 325 linux_msg(td, "copyout error %d", error); 326 return (error); 327 } 328 329 iov.iov_len = len; 330 error = copyout(&iov, (void *)data, sizeof(iov)); 331 if (error != 0) { 332 linux_msg(td, "iov copyout error %d", error); 333 return (error); 334 } 335 336 return (error); 337 } 338 339 static int 340 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) 341 { 342 343 switch (addr) { 344 case LINUX_NT_PRSTATUS: 345 return (linux_ptrace_getregset_prstatus(td, pid, data)); 346 case LINUX_NT_PRFPREG: 347 linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; " 348 "returning EINVAL"); 349 return (EINVAL); 350 case LINUX_NT_X86_XSTATE: 351 linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; " 352 "returning EINVAL"); 353 return (EINVAL); 354 default: 355 linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; " 356 "returning EINVAL", addr); 357 return (EINVAL); 358 } 359 } 360 361 static int 362 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data) 363 { 364 365 linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL"); 366 return (EINVAL); 367 } 368 369 static int 370 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, 371 l_ulong len, l_ulong data) 372 { 373 struct ptrace_lwpinfo lwpinfo; 374 struct ptrace_sc_ret sr; 375 struct reg b_reg; 376 struct syscall_info si; 377 int error; 378 379 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo)); 380 if (error != 0) { 381 linux_msg(td, "PT_LWPINFO failed with error %d", error); 382 return (error); 383 } 384 385 memset(&si, 0, sizeof(si)); 386 387 if (lwpinfo.pl_flags & PL_FLAG_SCE) { 388 si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY; 389 si.entry.nr = lwpinfo.pl_syscall_code; 390 /* 391 * The use of PT_GET_SC_ARGS there is special, 392 * implementation of PT_GET_SC_ARGS for Linux-ABI 393 * callers emulates Linux bug which strace(1) depends 394 * on: at initialization it tests whether ptrace works 395 * by calling close(2), or some other single-argument 396 * syscall, _with six arguments_, and then verifies 397 * whether it can fetch them all using this API; 398 * otherwise it bails out. 399 */ 400 error = kern_ptrace(td, PT_GET_SC_ARGS, pid, 401 &si.entry.args, sizeof(si.entry.args)); 402 if (error != 0) { 403 linux_msg(td, "PT_GET_SC_ARGS failed with error %d", 404 error); 405 return (error); 406 } 407 } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { 408 si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT; 409 error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr)); 410 411 if (error != 0) { 412 linux_msg(td, "PT_GET_SC_RET failed with error %d", 413 error); 414 return (error); 415 } 416 417 if (sr.sr_error == 0) { 418 si.exit.rval = sr.sr_retval[0]; 419 si.exit.is_error = 0; 420 } else if (sr.sr_error == EJUSTRETURN) { 421 /* 422 * EJUSTRETURN means the actual value to return 423 * has already been put into td_frame; instead 424 * of extracting it and trying to determine whether 425 * it's an error or not just bail out and let 426 * the ptracing process fall back to another method. 427 */ 428 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; 429 } else if (sr.sr_error == ERESTART) { 430 si.exit.rval = -LINUX_ERESTARTSYS; 431 si.exit.is_error = 1; 432 } else { 433 si.exit.rval = bsd_to_linux_errno(sr.sr_error); 434 si.exit.is_error = 1; 435 } 436 } else { 437 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE; 438 } 439 440 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0); 441 if (error != 0) 442 return (error); 443 444 linux_ptrace_get_syscall_info_machdep(&b_reg, &si); 445 446 len = MIN(len, sizeof(si)); 447 error = copyout(&si, (void *)data, len); 448 if (error == 0) 449 td->td_retval[0] = sizeof(si); 450 451 return (error); 452 } 453 454 int 455 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) 456 { 457 void *addr; 458 pid_t pid; 459 int error, sig; 460 461 if (!allow_ptrace) 462 return (ENOSYS); 463 464 pid = (pid_t)uap->pid; 465 addr = (void *)uap->addr; 466 467 switch (uap->req) { 468 case LINUX_PTRACE_TRACEME: 469 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0); 470 break; 471 case LINUX_PTRACE_PEEKTEXT: 472 case LINUX_PTRACE_PEEKDATA: 473 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data); 474 if (error != 0) 475 goto out; 476 /* 477 * Linux expects this syscall to read 64 bits, not 32. 478 */ 479 error = linux_ptrace_peek(td, pid, 480 (void *)(uap->addr + 4), (void *)(uap->data + 4)); 481 break; 482 case LINUX_PTRACE_PEEKUSER: 483 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data); 484 break; 485 case LINUX_PTRACE_POKETEXT: 486 case LINUX_PTRACE_POKEDATA: 487 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data); 488 if (error != 0) 489 goto out; 490 /* 491 * Linux expects this syscall to write 64 bits, not 32. 492 */ 493 error = kern_ptrace(td, PT_WRITE_D, pid, 494 (void *)(uap->addr + 4), uap->data >> 32); 495 break; 496 case LINUX_PTRACE_POKEUSER: 497 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data); 498 break; 499 case LINUX_PTRACE_CONT: 500 error = map_signum(uap->data, &sig); 501 if (error != 0) 502 break; 503 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig); 504 break; 505 case LINUX_PTRACE_KILL: 506 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data); 507 break; 508 case LINUX_PTRACE_SINGLESTEP: 509 error = map_signum(uap->data, &sig); 510 if (error != 0) 511 break; 512 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig); 513 break; 514 case LINUX_PTRACE_GETREGS: 515 error = linux_ptrace_getregs(td, pid, (void *)uap->data); 516 break; 517 case LINUX_PTRACE_SETREGS: 518 error = linux_ptrace_setregs(td, pid, (void *)uap->data); 519 break; 520 case LINUX_PTRACE_ATTACH: 521 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); 522 break; 523 case LINUX_PTRACE_DETACH: 524 error = map_signum(uap->data, &sig); 525 if (error != 0) 526 break; 527 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig); 528 break; 529 case LINUX_PTRACE_SYSCALL: 530 error = map_signum(uap->data, &sig); 531 if (error != 0) 532 break; 533 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig); 534 break; 535 case LINUX_PTRACE_SETOPTIONS: 536 error = linux_ptrace_setoptions(td, pid, uap->data); 537 break; 538 case LINUX_PTRACE_GETEVENTMSG: 539 error = linux_ptrace_geteventmsg(td, pid, uap->data); 540 break; 541 case LINUX_PTRACE_GETSIGINFO: 542 error = linux_ptrace_getsiginfo(td, pid, uap->data); 543 break; 544 case LINUX_PTRACE_GETREGSET: 545 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data); 546 break; 547 case LINUX_PTRACE_SEIZE: 548 error = linux_ptrace_seize(td, pid, uap->addr, uap->data); 549 break; 550 case LINUX_PTRACE_GET_SYSCALL_INFO: 551 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data); 552 break; 553 default: 554 linux_msg(td, "ptrace(%ld, ...) not implemented; " 555 "returning EINVAL", uap->req); 556 error = EINVAL; 557 break; 558 } 559 560 out: 561 if (error == EBUSY) 562 error = ESRCH; 563 564 return (error); 565 } 566