1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2017 Edward Tomasz Napierala <[email protected]>
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 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/lock.h>
37 #include <sys/proc.h>
38 #include <sys/ptrace.h>
39 #include <sys/sx.h>
40 #include <sys/syscallsubr.h>
41
42 #include <machine/pcb.h>
43 #include <machine/reg.h>
44
45 #include <amd64/linux/linux.h>
46 #include <amd64/linux/linux_proto.h>
47 #include <compat/linux/linux_emul.h>
48 #include <compat/linux/linux_errno.h>
49 #include <compat/linux/linux_misc.h>
50 #include <compat/linux/linux_signal.h>
51 #include <compat/linux/linux_util.h>
52
53 #define LINUX_PTRACE_TRACEME 0
54 #define LINUX_PTRACE_PEEKTEXT 1
55 #define LINUX_PTRACE_PEEKDATA 2
56 #define LINUX_PTRACE_PEEKUSER 3
57 #define LINUX_PTRACE_POKETEXT 4
58 #define LINUX_PTRACE_POKEDATA 5
59 #define LINUX_PTRACE_POKEUSER 6
60 #define LINUX_PTRACE_CONT 7
61 #define LINUX_PTRACE_KILL 8
62 #define LINUX_PTRACE_SINGLESTEP 9
63 #define LINUX_PTRACE_GETREGS 12
64 #define LINUX_PTRACE_SETREGS 13
65 #define LINUX_PTRACE_GETFPREGS 14
66 #define LINUX_PTRACE_SETFPREGS 15
67 #define LINUX_PTRACE_ATTACH 16
68 #define LINUX_PTRACE_DETACH 17
69 #define LINUX_PTRACE_SYSCALL 24
70 #define LINUX_PTRACE_SETOPTIONS 0x4200
71 #define LINUX_PTRACE_GETEVENTMSG 0x4201
72 #define LINUX_PTRACE_GETSIGINFO 0x4202
73 #define LINUX_PTRACE_GETREGSET 0x4204
74 #define LINUX_PTRACE_SEIZE 0x4206
75 #define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e
76
77 #define LINUX_PTRACE_EVENT_EXEC 4
78 #define LINUX_PTRACE_EVENT_EXIT 6
79
80 #define LINUX_PTRACE_O_TRACESYSGOOD 1
81 #define LINUX_PTRACE_O_TRACEFORK 2
82 #define LINUX_PTRACE_O_TRACEVFORK 4
83 #define LINUX_PTRACE_O_TRACECLONE 8
84 #define LINUX_PTRACE_O_TRACEEXEC 16
85 #define LINUX_PTRACE_O_TRACEVFORKDONE 32
86 #define LINUX_PTRACE_O_TRACEEXIT 64
87 #define LINUX_PTRACE_O_TRACESECCOMP 128
88 #define LINUX_PTRACE_O_EXITKILL 1048576
89 #define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152
90
91 #define LINUX_NT_PRSTATUS 0x1
92 #define LINUX_NT_PRFPREG 0x2
93 #define LINUX_NT_X86_XSTATE 0x202
94
95 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \
96 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \
97 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \
98 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \
99 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \
100 LINUX_PTRACE_O_SUSPEND_SECCOMP)
101
102 #define LINUX_PTRACE_SYSCALL_INFO_NONE 0
103 #define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1
104 #define LINUX_PTRACE_SYSCALL_INFO_EXIT 2
105
106 #define LINUX_PTRACE_PEEKUSER_ORIG_RAX 120
107 #define LINUX_PTRACE_PEEKUSER_RIP 128
108 #define LINUX_PTRACE_PEEKUSER_CS 136
109 #define LINUX_PTRACE_PEEKUSER_DS 184
110
111 #define LINUX_ARCH_AMD64 0xc000003e
112
113 static int
map_signum(int lsig,int * bsigp)114 map_signum(int lsig, int *bsigp)
115 {
116 int bsig;
117
118 if (lsig == 0) {
119 *bsigp = 0;
120 return (0);
121 }
122
123 if (lsig < 0 || lsig > LINUX_SIGRTMAX)
124 return (EINVAL);
125
126 bsig = linux_to_bsd_signal(lsig);
127 if (bsig == SIGSTOP)
128 bsig = 0;
129
130 *bsigp = bsig;
131 return (0);
132 }
133
134 int
linux_ptrace_status(struct thread * td,pid_t pid,int status)135 linux_ptrace_status(struct thread *td, pid_t pid, int status)
136 {
137 struct ptrace_lwpinfo lwpinfo;
138 struct linux_pemuldata *pem;
139 register_t saved_retval;
140 int error;
141
142 saved_retval = td->td_retval[0];
143 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
144 td->td_retval[0] = saved_retval;
145 if (error != 0) {
146 linux_msg(td, "PT_LWPINFO failed with error %d", error);
147 return (status);
148 }
149
150 pem = pem_find(td->td_proc);
151 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
152
153 LINUX_PEM_SLOCK(pem);
154 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
155 lwpinfo.pl_flags & PL_FLAG_SCE)
156 status |= (LINUX_SIGTRAP | 0x80) << 8;
157 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
158 lwpinfo.pl_flags & PL_FLAG_SCX) {
159 if (lwpinfo.pl_flags & PL_FLAG_EXEC)
160 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8;
161 else
162 status |= (LINUX_SIGTRAP | 0x80) << 8;
163 }
164 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
165 lwpinfo.pl_flags & PL_FLAG_EXITED)
166 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
167 LINUX_PEM_SUNLOCK(pem);
168
169 return (status);
170 }
171
172 struct linux_pt_reg {
173 l_ulong r15;
174 l_ulong r14;
175 l_ulong r13;
176 l_ulong r12;
177 l_ulong rbp;
178 l_ulong rbx;
179 l_ulong r11;
180 l_ulong r10;
181 l_ulong r9;
182 l_ulong r8;
183 l_ulong rax;
184 l_ulong rcx;
185 l_ulong rdx;
186 l_ulong rsi;
187 l_ulong rdi;
188 l_ulong orig_rax;
189 l_ulong rip;
190 l_ulong cs;
191 l_ulong eflags;
192 l_ulong rsp;
193 l_ulong ss;
194 };
195
196 struct syscall_info {
197 uint8_t op;
198 uint32_t arch;
199 uint64_t instruction_pointer;
200 uint64_t stack_pointer;
201 union {
202 struct {
203 uint64_t nr;
204 uint64_t args[6];
205 } entry;
206 struct {
207 int64_t rval;
208 uint8_t is_error;
209 } exit;
210 struct {
211 uint64_t nr;
212 uint64_t args[6];
213 uint32_t ret_data;
214 } seccomp;
215 };
216 };
217
218 /*
219 * Translate amd64 ptrace registers between Linux and FreeBSD formats.
220 * The translation is pretty straighforward, for all registers but
221 * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
222 */
223 static void
map_regs_to_linux(struct reg * b_reg,struct linux_pt_reg * l_reg)224 map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
225 {
226
227 l_reg->r15 = b_reg->r_r15;
228 l_reg->r14 = b_reg->r_r14;
229 l_reg->r13 = b_reg->r_r13;
230 l_reg->r12 = b_reg->r_r12;
231 l_reg->rbp = b_reg->r_rbp;
232 l_reg->rbx = b_reg->r_rbx;
233 l_reg->r11 = b_reg->r_r11;
234 l_reg->r10 = b_reg->r_r10;
235 l_reg->r9 = b_reg->r_r9;
236 l_reg->r8 = b_reg->r_r8;
237 l_reg->rax = b_reg->r_rax;
238 l_reg->rcx = b_reg->r_rcx;
239 l_reg->rdx = b_reg->r_rdx;
240 l_reg->rsi = b_reg->r_rsi;
241 l_reg->rdi = b_reg->r_rdi;
242 l_reg->orig_rax = b_reg->r_rax;
243 l_reg->rip = b_reg->r_rip;
244 l_reg->cs = b_reg->r_cs;
245 l_reg->eflags = b_reg->r_rflags;
246 l_reg->rsp = b_reg->r_rsp;
247 l_reg->ss = b_reg->r_ss;
248 }
249
250 void
bsd_to_linux_regset(struct reg * b_reg,struct linux_pt_regset * l_regset)251 bsd_to_linux_regset(struct reg *b_reg, struct linux_pt_regset *l_regset)
252 {
253
254 l_regset->r15 = b_reg->r_r15;
255 l_regset->r14 = b_reg->r_r14;
256 l_regset->r13 = b_reg->r_r13;
257 l_regset->r12 = b_reg->r_r12;
258 l_regset->rbp = b_reg->r_rbp;
259 l_regset->rbx = b_reg->r_rbx;
260 l_regset->r11 = b_reg->r_r11;
261 l_regset->r10 = b_reg->r_r10;
262 l_regset->r9 = b_reg->r_r9;
263 l_regset->r8 = b_reg->r_r8;
264 l_regset->rax = b_reg->r_rax;
265 l_regset->rcx = b_reg->r_rcx;
266 l_regset->rdx = b_reg->r_rdx;
267 l_regset->rsi = b_reg->r_rsi;
268 l_regset->rdi = b_reg->r_rdi;
269 l_regset->orig_rax = b_reg->r_rax;
270 l_regset->rip = b_reg->r_rip;
271 l_regset->cs = b_reg->r_cs;
272 l_regset->eflags = b_reg->r_rflags;
273 l_regset->rsp = b_reg->r_rsp;
274 l_regset->ss = b_reg->r_ss;
275 l_regset->fs_base = 0;
276 l_regset->gs_base = 0;
277 l_regset->ds = b_reg->r_ds;
278 l_regset->es = b_reg->r_es;
279 l_regset->fs = b_reg->r_fs;
280 l_regset->gs = b_reg->r_gs;
281 }
282
283 static void
map_regs_from_linux(struct reg * b_reg,struct linux_pt_reg * l_reg)284 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
285 {
286 b_reg->r_r15 = l_reg->r15;
287 b_reg->r_r14 = l_reg->r14;
288 b_reg->r_r13 = l_reg->r13;
289 b_reg->r_r12 = l_reg->r12;
290 b_reg->r_r11 = l_reg->r11;
291 b_reg->r_r10 = l_reg->r10;
292 b_reg->r_r9 = l_reg->r9;
293 b_reg->r_r8 = l_reg->r8;
294 b_reg->r_rdi = l_reg->rdi;
295 b_reg->r_rsi = l_reg->rsi;
296 b_reg->r_rbp = l_reg->rbp;
297 b_reg->r_rbx = l_reg->rbx;
298 b_reg->r_rdx = l_reg->rdx;
299 b_reg->r_rcx = l_reg->rcx;
300 b_reg->r_rax = l_reg->rax;
301
302 /*
303 * XXX: Are zeroes the right thing to put here?
304 */
305 b_reg->r_trapno = 0;
306 b_reg->r_fs = 0;
307 b_reg->r_gs = 0;
308 b_reg->r_err = 0;
309 b_reg->r_es = 0;
310 b_reg->r_ds = 0;
311
312 b_reg->r_rip = l_reg->rip;
313 b_reg->r_cs = l_reg->cs;
314 b_reg->r_rflags = l_reg->eflags;
315 b_reg->r_rsp = l_reg->rsp;
316 b_reg->r_ss = l_reg->ss;
317 }
318
319 static int
linux_ptrace_peek(struct thread * td,pid_t pid,void * addr,void * data)320 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
321 {
322 int error;
323
324 error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
325 if (error == 0)
326 error = copyout(td->td_retval, data, sizeof(l_int));
327 else if (error == ENOMEM)
328 error = EIO;
329 td->td_retval[0] = error;
330
331 return (error);
332 }
333
334 static int
linux_ptrace_peekuser(struct thread * td,pid_t pid,void * addr,void * data)335 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
336 {
337 struct reg b_reg;
338 uint64_t val;
339 int error;
340
341 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
342 if (error != 0)
343 return (error);
344
345 switch ((uintptr_t)addr) {
346 case LINUX_PTRACE_PEEKUSER_ORIG_RAX:
347 val = b_reg.r_rax;
348 break;
349 case LINUX_PTRACE_PEEKUSER_RIP:
350 val = b_reg.r_rip;
351 break;
352 case LINUX_PTRACE_PEEKUSER_CS:
353 val = b_reg.r_cs;
354 break;
355 case LINUX_PTRACE_PEEKUSER_DS:
356 val = b_reg.r_ds;
357 break;
358 default:
359 linux_msg(td, "PTRACE_PEEKUSER offset %ld not implemented; "
360 "returning EINVAL", (uintptr_t)addr);
361 return (EINVAL);
362 }
363
364 error = copyout(&val, data, sizeof(val));
365 td->td_retval[0] = error;
366
367 return (error);
368 }
369
370 static int
linux_ptrace_pokeuser(struct thread * td,pid_t pid,void * addr,void * data)371 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
372 {
373
374 linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
375 return (EINVAL);
376 }
377
378 static int
linux_ptrace_setoptions(struct thread * td,pid_t pid,l_ulong data)379 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
380 {
381 struct linux_pemuldata *pem;
382 int mask;
383
384 mask = 0;
385
386 if (data & ~LINUX_PTRACE_O_MASK) {
387 linux_msg(td, "unknown ptrace option %lx set; "
388 "returning EINVAL",
389 data & ~LINUX_PTRACE_O_MASK);
390 return (EINVAL);
391 }
392
393 pem = pem_find(td->td_proc);
394 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
395
396 /*
397 * PTRACE_O_EXITKILL is ignored, we do that by default.
398 */
399
400 LINUX_PEM_XLOCK(pem);
401 if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
402 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
403 } else {
404 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
405 }
406 LINUX_PEM_XUNLOCK(pem);
407
408 if (data & LINUX_PTRACE_O_TRACEFORK)
409 mask |= PTRACE_FORK;
410
411 if (data & LINUX_PTRACE_O_TRACEVFORK)
412 mask |= PTRACE_VFORK;
413
414 if (data & LINUX_PTRACE_O_TRACECLONE)
415 mask |= PTRACE_VFORK;
416
417 if (data & LINUX_PTRACE_O_TRACEEXEC)
418 mask |= PTRACE_EXEC;
419
420 if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
421 mask |= PTRACE_VFORK; /* XXX: Close enough? */
422
423 if (data & LINUX_PTRACE_O_TRACEEXIT) {
424 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
425 } else {
426 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
427 }
428
429 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
430 }
431
432 static int
linux_ptrace_geteventmsg(struct thread * td,pid_t pid,l_ulong data)433 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data)
434 {
435
436 linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL");
437 return (EINVAL);
438 }
439
440 static int
linux_ptrace_getsiginfo(struct thread * td,pid_t pid,l_ulong data)441 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
442 {
443 struct ptrace_lwpinfo lwpinfo;
444 l_siginfo_t l_siginfo;
445 int error, sig;
446
447 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
448 if (error != 0) {
449 linux_msg(td, "PT_LWPINFO failed with error %d", error);
450 return (error);
451 }
452
453 if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
454 error = EINVAL;
455 linux_msg(td, "no PL_FLAG_SI, returning %d", error);
456 return (error);
457 }
458
459 sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
460 memset(&l_siginfo, 0, sizeof(l_siginfo));
461 siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
462 error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
463 return (error);
464 }
465
466 static int
linux_ptrace_getregs(struct thread * td,pid_t pid,void * data)467 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
468 {
469 struct ptrace_lwpinfo lwpinfo;
470 struct reg b_reg;
471 struct linux_pt_reg l_reg;
472 int error;
473
474 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
475 if (error != 0)
476 return (error);
477
478 map_regs_to_linux(&b_reg, &l_reg);
479
480 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
481 if (error != 0) {
482 linux_msg(td, "PT_LWPINFO failed with error %d", error);
483 return (error);
484 }
485 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
486 /*
487 * The strace(1) utility depends on RAX being set to -ENOSYS
488 * on syscall entry; otherwise it loops printing those:
489 *
490 * [ Process PID=928 runs in 64 bit mode. ]
491 * [ Process PID=928 runs in x32 mode. ]
492 */
493 l_reg.rax = -38; /* -ENOSYS */
494
495 /*
496 * Undo the mangling done in exception.S:fast_syscall_common().
497 */
498 l_reg.r10 = l_reg.rcx;
499 }
500
501 error = copyout(&l_reg, (void *)data, sizeof(l_reg));
502 return (error);
503 }
504
505 static int
linux_ptrace_setregs(struct thread * td,pid_t pid,void * data)506 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
507 {
508 struct reg b_reg;
509 struct linux_pt_reg l_reg;
510 int error;
511
512 error = copyin(data, &l_reg, sizeof(l_reg));
513 if (error != 0)
514 return (error);
515 map_regs_from_linux(&b_reg, &l_reg);
516 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
517 return (error);
518 }
519
520 static int
linux_ptrace_getregset_prstatus(struct thread * td,pid_t pid,l_ulong data)521 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
522 {
523 struct ptrace_lwpinfo lwpinfo;
524 struct reg b_reg;
525 struct linux_pt_regset l_regset;
526 struct iovec iov;
527 struct pcb *pcb;
528 size_t len;
529 int error;
530
531 error = copyin((const void *)data, &iov, sizeof(iov));
532 if (error != 0) {
533 linux_msg(td, "copyin error %d", error);
534 return (error);
535 }
536
537 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
538 if (error != 0)
539 return (error);
540
541 pcb = td->td_pcb;
542 if (td == curthread)
543 update_pcb_bases(pcb);
544
545 bsd_to_linux_regset(&b_reg, &l_regset);
546 l_regset.fs_base = pcb->pcb_fsbase;
547 l_regset.gs_base = pcb->pcb_gsbase;
548
549 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
550 if (error != 0) {
551 linux_msg(td, "PT_LWPINFO failed with error %d", error);
552 return (error);
553 }
554 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
555 /*
556 * Undo the mangling done in exception.S:fast_syscall_common().
557 */
558 l_regset.r10 = l_regset.rcx;
559 }
560
561 if (lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) {
562 /*
563 * In Linux, the syscall number - passed to the syscall
564 * as rax - is preserved in orig_rax; rax gets overwritten
565 * with syscall return value.
566 */
567 l_regset.orig_rax = lwpinfo.pl_syscall_code;
568 }
569
570 len = MIN(iov.iov_len, sizeof(l_regset));
571 error = copyout(&l_regset, (void *)iov.iov_base, len);
572 if (error != 0) {
573 linux_msg(td, "copyout error %d", error);
574 return (error);
575 }
576
577 iov.iov_len = len;
578 error = copyout(&iov, (void *)data, sizeof(iov));
579 if (error != 0) {
580 linux_msg(td, "iov copyout error %d", error);
581 return (error);
582 }
583
584 return (error);
585 }
586
587 static int
linux_ptrace_getregset(struct thread * td,pid_t pid,l_ulong addr,l_ulong data)588 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
589 {
590
591 switch (addr) {
592 case LINUX_NT_PRSTATUS:
593 return (linux_ptrace_getregset_prstatus(td, pid, data));
594 case LINUX_NT_PRFPREG:
595 linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; "
596 "returning EINVAL");
597 return (EINVAL);
598 case LINUX_NT_X86_XSTATE:
599 linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; "
600 "returning EINVAL");
601 return (EINVAL);
602 default:
603 linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; "
604 "returning EINVAL", addr);
605 return (EINVAL);
606 }
607 }
608
609 static int
linux_ptrace_seize(struct thread * td,pid_t pid,l_ulong addr,l_ulong data)610 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
611 {
612
613 linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
614 return (EINVAL);
615 }
616
617 static int
linux_ptrace_get_syscall_info(struct thread * td,pid_t pid,l_ulong len,l_ulong data)618 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid,
619 l_ulong len, l_ulong data)
620 {
621 struct ptrace_lwpinfo lwpinfo;
622 struct ptrace_sc_ret sr;
623 struct reg b_reg;
624 struct syscall_info si;
625 int error;
626
627 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
628 if (error != 0) {
629 linux_msg(td, "PT_LWPINFO failed with error %d", error);
630 return (error);
631 }
632
633 memset(&si, 0, sizeof(si));
634
635 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
636 si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY;
637 si.entry.nr = lwpinfo.pl_syscall_code;
638 /*
639 * The use of PT_GET_SC_ARGS there is special,
640 * implementation of PT_GET_SC_ARGS for Linux-ABI
641 * callers emulates Linux bug which strace(1) depends
642 * on: at initialization it tests whether ptrace works
643 * by calling close(2), or some other single-argument
644 * syscall, _with six arguments_, and then verifies
645 * whether it can fetch them all using this API;
646 * otherwise it bails out.
647 */
648 error = kern_ptrace(td, PT_GET_SC_ARGS, pid,
649 &si.entry.args, sizeof(si.entry.args));
650 if (error != 0) {
651 linux_msg(td, "PT_GET_SC_ARGS failed with error %d",
652 error);
653 return (error);
654 }
655 } else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
656 si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT;
657 error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr));
658
659 if (error != 0) {
660 linux_msg(td, "PT_GET_SC_RET failed with error %d",
661 error);
662 return (error);
663 }
664
665 if (sr.sr_error == 0) {
666 si.exit.rval = sr.sr_retval[0];
667 si.exit.is_error = 0;
668 } else if (sr.sr_error == EJUSTRETURN) {
669 /*
670 * EJUSTRETURN means the actual value to return
671 * has already been put into td_frame; instead
672 * of extracting it and trying to determine whether
673 * it's an error or not just bail out and let
674 * the ptracing process fall back to another method.
675 */
676 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
677 } else if (sr.sr_error == ERESTART) {
678 si.exit.rval = -LINUX_ERESTARTSYS;
679 si.exit.is_error = 1;
680 } else {
681 si.exit.rval = bsd_to_linux_errno(sr.sr_error);
682 si.exit.is_error = 1;
683 }
684 } else {
685 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
686 }
687
688 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
689 if (error != 0)
690 return (error);
691
692 si.arch = LINUX_ARCH_AMD64;
693 si.instruction_pointer = b_reg.r_rip;
694 si.stack_pointer = b_reg.r_rsp;
695
696 len = MIN(len, sizeof(si));
697 error = copyout(&si, (void *)data, len);
698 if (error == 0)
699 td->td_retval[0] = sizeof(si);
700
701 return (error);
702 }
703
704 int
linux_ptrace(struct thread * td,struct linux_ptrace_args * uap)705 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
706 {
707 void *addr;
708 pid_t pid;
709 int error, sig;
710
711 if (!allow_ptrace)
712 return (ENOSYS);
713
714 pid = (pid_t)uap->pid;
715 addr = (void *)uap->addr;
716
717 switch (uap->req) {
718 case LINUX_PTRACE_TRACEME:
719 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
720 break;
721 case LINUX_PTRACE_PEEKTEXT:
722 case LINUX_PTRACE_PEEKDATA:
723 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
724 if (error != 0)
725 goto out;
726 /*
727 * Linux expects this syscall to read 64 bits, not 32.
728 */
729 error = linux_ptrace_peek(td, pid,
730 (void *)(uap->addr + 4), (void *)(uap->data + 4));
731 break;
732 case LINUX_PTRACE_PEEKUSER:
733 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
734 break;
735 case LINUX_PTRACE_POKETEXT:
736 case LINUX_PTRACE_POKEDATA:
737 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
738 if (error != 0)
739 goto out;
740 /*
741 * Linux expects this syscall to write 64 bits, not 32.
742 */
743 error = kern_ptrace(td, PT_WRITE_D, pid,
744 (void *)(uap->addr + 4), uap->data >> 32);
745 break;
746 case LINUX_PTRACE_POKEUSER:
747 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
748 break;
749 case LINUX_PTRACE_CONT:
750 error = map_signum(uap->data, &sig);
751 if (error != 0)
752 break;
753 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
754 break;
755 case LINUX_PTRACE_KILL:
756 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
757 break;
758 case LINUX_PTRACE_SINGLESTEP:
759 error = map_signum(uap->data, &sig);
760 if (error != 0)
761 break;
762 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
763 break;
764 case LINUX_PTRACE_GETREGS:
765 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
766 break;
767 case LINUX_PTRACE_SETREGS:
768 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
769 break;
770 case LINUX_PTRACE_ATTACH:
771 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
772 break;
773 case LINUX_PTRACE_DETACH:
774 error = map_signum(uap->data, &sig);
775 if (error != 0)
776 break;
777 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
778 break;
779 case LINUX_PTRACE_SYSCALL:
780 error = map_signum(uap->data, &sig);
781 if (error != 0)
782 break;
783 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
784 break;
785 case LINUX_PTRACE_SETOPTIONS:
786 error = linux_ptrace_setoptions(td, pid, uap->data);
787 break;
788 case LINUX_PTRACE_GETEVENTMSG:
789 error = linux_ptrace_geteventmsg(td, pid, uap->data);
790 break;
791 case LINUX_PTRACE_GETSIGINFO:
792 error = linux_ptrace_getsiginfo(td, pid, uap->data);
793 break;
794 case LINUX_PTRACE_GETREGSET:
795 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
796 break;
797 case LINUX_PTRACE_SEIZE:
798 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
799 break;
800 case LINUX_PTRACE_GET_SYSCALL_INFO:
801 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
802 break;
803 default:
804 linux_msg(td, "ptrace(%ld, ...) not implemented; "
805 "returning EINVAL", uap->req);
806 error = EINVAL;
807 break;
808 }
809
810 out:
811 if (error == EBUSY)
812 error = ESRCH;
813
814 return (error);
815 }
816