linux_ptrace.c revision 314210
1/*- 2 * Copyright (c) 2001 Alexander Kabaev 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/11/sys/i386/linux/linux_ptrace.c 314210 2017-02-24 16:02:01Z kib $"); 31 32#include "opt_cpu.h" 33 34#include <sys/param.h> 35#include <sys/lock.h> 36#include <sys/mutex.h> 37#include <sys/proc.h> 38#include <sys/ptrace.h> 39#include <sys/syscallsubr.h> 40#include <sys/systm.h> 41 42#include <machine/md_var.h> 43#include <machine/pcb.h> 44#include <machine/reg.h> 45 46#include <i386/linux/linux.h> 47#include <i386/linux/linux_proto.h> 48#include <compat/linux/linux_signal.h> 49 50/* 51 * Linux ptrace requests numbers. Mostly identical to FreeBSD, 52 * except for MD ones and PT_ATTACH/PT_DETACH. 53 */ 54#define PTRACE_TRACEME 0 55#define PTRACE_PEEKTEXT 1 56#define PTRACE_PEEKDATA 2 57#define PTRACE_PEEKUSR 3 58#define PTRACE_POKETEXT 4 59#define PTRACE_POKEDATA 5 60#define PTRACE_POKEUSR 6 61#define PTRACE_CONT 7 62#define PTRACE_KILL 8 63#define PTRACE_SINGLESTEP 9 64 65#define PTRACE_ATTACH 16 66#define PTRACE_DETACH 17 67 68#define LINUX_PTRACE_SYSCALL 24 69 70#define PTRACE_GETREGS 12 71#define PTRACE_SETREGS 13 72#define PTRACE_GETFPREGS 14 73#define PTRACE_SETFPREGS 15 74#define PTRACE_GETFPXREGS 18 75#define PTRACE_SETFPXREGS 19 76 77#define PTRACE_SETOPTIONS 21 78 79/* 80 * Linux keeps debug registers at the following 81 * offset in the user struct 82 */ 83#define LINUX_DBREG_OFFSET 252 84#define LINUX_DBREG_SIZE (8*sizeof(l_int)) 85 86static __inline int 87map_signum(int signum) 88{ 89 90 signum = linux_to_bsd_signal(signum); 91 return ((signum == SIGSTOP)? 0 : signum); 92} 93 94struct linux_pt_reg { 95 l_long ebx; 96 l_long ecx; 97 l_long edx; 98 l_long esi; 99 l_long edi; 100 l_long ebp; 101 l_long eax; 102 l_int xds; 103 l_int xes; 104 l_int xfs; 105 l_int xgs; 106 l_long orig_eax; 107 l_long eip; 108 l_int xcs; 109 l_long eflags; 110 l_long esp; 111 l_int xss; 112}; 113 114/* 115 * Translate i386 ptrace registers between Linux and FreeBSD formats. 116 * The translation is pretty straighforward, for all registers, but 117 * orig_eax on Linux side and r_trapno and r_err in FreeBSD 118 */ 119static void 120map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) 121{ 122 linux_r->ebx = bsd_r->r_ebx; 123 linux_r->ecx = bsd_r->r_ecx; 124 linux_r->edx = bsd_r->r_edx; 125 linux_r->esi = bsd_r->r_esi; 126 linux_r->edi = bsd_r->r_edi; 127 linux_r->ebp = bsd_r->r_ebp; 128 linux_r->eax = bsd_r->r_eax; 129 linux_r->xds = bsd_r->r_ds; 130 linux_r->xes = bsd_r->r_es; 131 linux_r->xfs = bsd_r->r_fs; 132 linux_r->xgs = bsd_r->r_gs; 133 linux_r->orig_eax = bsd_r->r_eax; 134 linux_r->eip = bsd_r->r_eip; 135 linux_r->xcs = bsd_r->r_cs; 136 linux_r->eflags = bsd_r->r_eflags; 137 linux_r->esp = bsd_r->r_esp; 138 linux_r->xss = bsd_r->r_ss; 139} 140 141static void 142map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r) 143{ 144 bsd_r->r_ebx = linux_r->ebx; 145 bsd_r->r_ecx = linux_r->ecx; 146 bsd_r->r_edx = linux_r->edx; 147 bsd_r->r_esi = linux_r->esi; 148 bsd_r->r_edi = linux_r->edi; 149 bsd_r->r_ebp = linux_r->ebp; 150 bsd_r->r_eax = linux_r->eax; 151 bsd_r->r_ds = linux_r->xds; 152 bsd_r->r_es = linux_r->xes; 153 bsd_r->r_fs = linux_r->xfs; 154 bsd_r->r_gs = linux_r->xgs; 155 bsd_r->r_eip = linux_r->eip; 156 bsd_r->r_cs = linux_r->xcs; 157 bsd_r->r_eflags = linux_r->eflags; 158 bsd_r->r_esp = linux_r->esp; 159 bsd_r->r_ss = linux_r->xss; 160} 161 162struct linux_pt_fpreg { 163 l_long cwd; 164 l_long swd; 165 l_long twd; 166 l_long fip; 167 l_long fcs; 168 l_long foo; 169 l_long fos; 170 l_long st_space[2*10]; 171}; 172 173static void 174map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) 175{ 176 linux_r->cwd = bsd_r->fpr_env[0]; 177 linux_r->swd = bsd_r->fpr_env[1]; 178 linux_r->twd = bsd_r->fpr_env[2]; 179 linux_r->fip = bsd_r->fpr_env[3]; 180 linux_r->fcs = bsd_r->fpr_env[4]; 181 linux_r->foo = bsd_r->fpr_env[5]; 182 linux_r->fos = bsd_r->fpr_env[6]; 183 bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space)); 184} 185 186static void 187map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r) 188{ 189 bsd_r->fpr_env[0] = linux_r->cwd; 190 bsd_r->fpr_env[1] = linux_r->swd; 191 bsd_r->fpr_env[2] = linux_r->twd; 192 bsd_r->fpr_env[3] = linux_r->fip; 193 bsd_r->fpr_env[4] = linux_r->fcs; 194 bsd_r->fpr_env[5] = linux_r->foo; 195 bsd_r->fpr_env[6] = linux_r->fos; 196 bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc)); 197} 198 199struct linux_pt_fpxreg { 200 l_ushort cwd; 201 l_ushort swd; 202 l_ushort twd; 203 l_ushort fop; 204 l_long fip; 205 l_long fcs; 206 l_long foo; 207 l_long fos; 208 l_long mxcsr; 209 l_long reserved; 210 l_long st_space[32]; 211 l_long xmm_space[32]; 212 l_long padding[56]; 213}; 214 215static int 216linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 217{ 218 219 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 220 if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0) 221 return (EIO); 222 bcopy(&get_pcb_user_save_td(td)->sv_xmm, fpxregs, sizeof(*fpxregs)); 223 return (0); 224} 225 226static int 227linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 228{ 229 230 PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); 231 if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0) 232 return (EIO); 233 bcopy(fpxregs, &get_pcb_user_save_td(td)->sv_xmm, sizeof(*fpxregs)); 234 return (0); 235} 236 237int 238linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) 239{ 240 union { 241 struct linux_pt_reg reg; 242 struct linux_pt_fpreg fpreg; 243 struct linux_pt_fpxreg fpxreg; 244 } r; 245 union { 246 struct reg bsd_reg; 247 struct fpreg bsd_fpreg; 248 struct dbreg bsd_dbreg; 249 } u; 250 void *addr; 251 pid_t pid; 252 int error, req; 253 254 error = 0; 255 256 /* by default, just copy data intact */ 257 req = uap->req; 258 pid = (pid_t)uap->pid; 259 addr = (void *)uap->addr; 260 261 switch (req) { 262 case PTRACE_TRACEME: 263 case PTRACE_POKETEXT: 264 case PTRACE_POKEDATA: 265 case PTRACE_KILL: 266 error = kern_ptrace(td, req, pid, addr, uap->data); 267 break; 268 case PTRACE_PEEKTEXT: 269 case PTRACE_PEEKDATA: { 270 /* need to preserve return value */ 271 int rval = td->td_retval[0]; 272 error = kern_ptrace(td, req, pid, addr, 0); 273 if (error == 0) 274 error = copyout(td->td_retval, (void *)uap->data, 275 sizeof(l_int)); 276 td->td_retval[0] = rval; 277 break; 278 } 279 case PTRACE_DETACH: 280 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, 281 map_signum(uap->data)); 282 break; 283 case PTRACE_SINGLESTEP: 284 case PTRACE_CONT: 285 error = kern_ptrace(td, req, pid, (void *)1, 286 map_signum(uap->data)); 287 break; 288 case PTRACE_ATTACH: 289 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data); 290 break; 291 case PTRACE_GETREGS: 292 /* Linux is using data where FreeBSD is using addr */ 293 error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); 294 if (error == 0) { 295 map_regs_to_linux(&u.bsd_reg, &r.reg); 296 error = copyout(&r.reg, (void *)uap->data, 297 sizeof(r.reg)); 298 } 299 break; 300 case PTRACE_SETREGS: 301 /* Linux is using data where FreeBSD is using addr */ 302 error = copyin((void *)uap->data, &r.reg, sizeof(r.reg)); 303 if (error == 0) { 304 map_regs_from_linux(&u.bsd_reg, &r.reg); 305 error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); 306 } 307 break; 308 case PTRACE_GETFPREGS: 309 /* Linux is using data where FreeBSD is using addr */ 310 error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0); 311 if (error == 0) { 312 map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg); 313 error = copyout(&r.fpreg, (void *)uap->data, 314 sizeof(r.fpreg)); 315 } 316 break; 317 case PTRACE_SETFPREGS: 318 /* Linux is using data where FreeBSD is using addr */ 319 error = copyin((void *)uap->data, &r.fpreg, sizeof(r.fpreg)); 320 if (error == 0) { 321 map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg); 322 error = kern_ptrace(td, PT_SETFPREGS, pid, 323 &u.bsd_fpreg, 0); 324 } 325 break; 326 case PTRACE_SETFPXREGS: 327 error = copyin((void *)uap->data, &r.fpxreg, sizeof(r.fpxreg)); 328 if (error) 329 break; 330 /* FALL THROUGH */ 331 case PTRACE_GETFPXREGS: { 332 struct proc *p; 333 struct thread *td2; 334 335 if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) { 336 static int once = 0; 337 if (!once) { 338 printf("linux: savexmm != linux_pt_fpxreg\n"); 339 once = 1; 340 } 341 error = EIO; 342 break; 343 } 344 345 if ((p = pfind(uap->pid)) == NULL) { 346 error = ESRCH; 347 break; 348 } 349 350 /* Exiting processes can't be debugged. */ 351 if ((p->p_flag & P_WEXIT) != 0) { 352 error = ESRCH; 353 goto fail; 354 } 355 356 if ((error = p_candebug(td, p)) != 0) 357 goto fail; 358 359 /* System processes can't be debugged. */ 360 if ((p->p_flag & P_SYSTEM) != 0) { 361 error = EINVAL; 362 goto fail; 363 } 364 365 /* not being traced... */ 366 if ((p->p_flag & P_TRACED) == 0) { 367 error = EPERM; 368 goto fail; 369 } 370 371 /* not being traced by YOU */ 372 if (p->p_pptr != td->td_proc) { 373 error = EBUSY; 374 goto fail; 375 } 376 377 /* not currently stopped */ 378 if (!P_SHOULDSTOP(p) || (p->p_flag & P_WAITED) == 0) { 379 error = EBUSY; 380 goto fail; 381 } 382 383 if (req == PTRACE_GETFPXREGS) { 384 _PHOLD(p); /* may block */ 385 td2 = FIRST_THREAD_IN_PROC(p); 386 error = linux_proc_read_fpxregs(td2, &r.fpxreg); 387 _PRELE(p); 388 PROC_UNLOCK(p); 389 if (error == 0) 390 error = copyout(&r.fpxreg, (void *)uap->data, 391 sizeof(r.fpxreg)); 392 } else { 393 /* clear dangerous bits exactly as Linux does*/ 394 r.fpxreg.mxcsr &= 0xffbf; 395 _PHOLD(p); /* may block */ 396 td2 = FIRST_THREAD_IN_PROC(p); 397 error = linux_proc_write_fpxregs(td2, &r.fpxreg); 398 _PRELE(p); 399 PROC_UNLOCK(p); 400 } 401 break; 402 403 fail: 404 PROC_UNLOCK(p); 405 break; 406 } 407 case PTRACE_PEEKUSR: 408 case PTRACE_POKEUSR: { 409 error = EIO; 410 411 /* check addr for alignment */ 412 if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1)) 413 break; 414 /* 415 * Allow linux programs to access register values in 416 * user struct. We simulate this through PT_GET/SETREGS 417 * as necessary. 418 */ 419 if (uap->addr < sizeof(struct linux_pt_reg)) { 420 error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0); 421 if (error != 0) 422 break; 423 424 map_regs_to_linux(&u.bsd_reg, &r.reg); 425 if (req == PTRACE_PEEKUSR) { 426 error = copyout((char *)&r.reg + uap->addr, 427 (void *)uap->data, sizeof(l_int)); 428 break; 429 } 430 431 *(l_int *)((char *)&r.reg + uap->addr) = 432 (l_int)uap->data; 433 434 map_regs_from_linux(&u.bsd_reg, &r.reg); 435 error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0); 436 } 437 438 /* 439 * Simulate debug registers access 440 */ 441 if (uap->addr >= LINUX_DBREG_OFFSET && 442 uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) { 443 error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg, 444 0); 445 if (error != 0) 446 break; 447 448 uap->addr -= LINUX_DBREG_OFFSET; 449 if (req == PTRACE_PEEKUSR) { 450 error = copyout((char *)&u.bsd_dbreg + 451 uap->addr, (void *)uap->data, 452 sizeof(l_int)); 453 break; 454 } 455 456 *(l_int *)((char *)&u.bsd_dbreg + uap->addr) = 457 uap->data; 458 error = kern_ptrace(td, PT_SETDBREGS, pid, 459 &u.bsd_dbreg, 0); 460 } 461 462 break; 463 } 464 case LINUX_PTRACE_SYSCALL: 465 /* fall through */ 466 default: 467 printf("linux: ptrace(%u, ...) not implemented\n", 468 (unsigned int)uap->req); 469 error = EINVAL; 470 break; 471 } 472 473 return (error); 474} 475