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