xref: /freebsd-13.1/sys/amd64/linux/linux_ptrace.c (revision bb726462)
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