xref: /f-stack/freebsd/i386/linux/linux_ptrace.c (revision 22ce4aff)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Alexander Kabaev
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
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 
86 static __inline int
map_signum(int signum)87 map_signum(int signum)
88 {
89 
90 	signum = linux_to_bsd_signal(signum);
91 	return ((signum == SIGSTOP)? 0 : signum);
92 }
93 
94 struct 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  */
119 static void
map_regs_to_linux(struct reg * bsd_r,struct linux_pt_reg * linux_r)120 map_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 
141 static void
map_regs_from_linux(struct reg * bsd_r,struct linux_pt_reg * linux_r)142 map_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 
162 struct 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 
173 static void
map_fpregs_to_linux(struct fpreg * bsd_r,struct linux_pt_fpreg * linux_r)174 map_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 
186 static void
map_fpregs_from_linux(struct fpreg * bsd_r,struct linux_pt_fpreg * linux_r)187 map_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 
199 struct 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 
215 static int
linux_proc_read_fpxregs(struct thread * td,struct linux_pt_fpxreg * fpxregs)216 linux_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 
226 static int
linux_proc_write_fpxregs(struct thread * td,struct linux_pt_fpxreg * fpxregs)227 linux_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 
237 int
linux_ptrace(struct thread * td,struct linux_ptrace_args * uap)238 linux_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