636 lines · 15.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* ptrace.c *//* By Ross Biro 1/23/92 *//* edited by Linus Torvalds *//* mangled further by Bob Manson (manson@santafe.edu) *//* more mutilation by David Mosberger (davidm@azstarnet.com) */ #include <linux/kernel.h>#include <linux/sched.h>#include <linux/sched/task_stack.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/errno.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/security.h>#include <linux/signal.h>#include <linux/audit.h>#include <linux/seccomp.h>#include <asm/syscall.h> #include <linux/uaccess.h>#include <asm/fpu.h> #include "proto.h"#include <linux/uio.h>#include <linux/regset.h> #define DEBUG	DBG_MEM#undef DEBUG #ifndef NT_FPREGSET#define NT_FPREGSET NT_PRFPREG#endif #ifdef DEBUGenum {	DBG_MEM		= (1<<0),	DBG_BPT		= (1<<1),	DBG_MEM_ALL	= (1<<2)};#define DBG(fac,args)	{if ((fac) & DEBUG) printk args;}#else#define DBG(fac,args)#endif #define BREAKINST	0x00000080	/* call_pal bpt */ /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. */ /* * Processes always block with the following stack-layout: * *  +================================+ <---- task + 2*PAGE_SIZE *  | PALcode saved frame (ps, pc,   | ^ *  | gp, a0, a1, a2)		     | | *  +================================+ | struct pt_regs *  |	        		     | | *  | frame generated by SAVE_ALL    | | *  |	        		     | v *  +================================+ *  |	        		     | ^ *  | frame saved by do_switch_stack | | struct switch_stack *  |	        		     | v *  +================================+ */ /*  * The following table maps a register index into the stack offset at * which the register is saved.  Register indices are 0-31 for integer * regs, 32-63 for fp regs, and 64 for the pc.  Notice that sp and * zero have no stack-slot and need to be treated specially (see * get_reg/put_reg below). */enum {	REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64}; #define PT_REG(reg) \  (PAGE_SIZE*2 - sizeof(struct pt_regs) + offsetof(struct pt_regs, reg)) #define SW_REG(reg) \ (PAGE_SIZE*2 - sizeof(struct pt_regs) - sizeof(struct switch_stack) \  + offsetof(struct switch_stack, reg)) #define FP_REG(reg) (offsetof(struct thread_info, reg)) static int regoff[] = {	PT_REG(	   r0), PT_REG(	   r1), PT_REG(	   r2), PT_REG(	  r3),	PT_REG(	   r4), PT_REG(	   r5), PT_REG(	   r6), PT_REG(	  r7),	PT_REG(	   r8), SW_REG(	   r9), SW_REG(	  r10), SW_REG(	 r11),	SW_REG(	  r12), SW_REG(	  r13), SW_REG(	  r14), SW_REG(	 r15),	PT_REG(	  r16), PT_REG(	  r17), PT_REG(	  r18), PT_REG(	 r19),	PT_REG(	  r20), PT_REG(	  r21), PT_REG(	  r22), PT_REG(	 r23),	PT_REG(	  r24), PT_REG(	  r25), PT_REG(	  r26), PT_REG(	 r27),	PT_REG(	  r28), PT_REG(	   gp),		   -1,		   -1,	FP_REG(fp[ 0]), FP_REG(fp[ 1]), FP_REG(fp[ 2]), FP_REG(fp[ 3]),	FP_REG(fp[ 4]), FP_REG(fp[ 5]), FP_REG(fp[ 6]), FP_REG(fp[ 7]),	FP_REG(fp[ 8]), FP_REG(fp[ 9]), FP_REG(fp[10]), FP_REG(fp[11]),	FP_REG(fp[12]), FP_REG(fp[13]), FP_REG(fp[14]), FP_REG(fp[15]),	FP_REG(fp[16]), FP_REG(fp[17]), FP_REG(fp[18]), FP_REG(fp[19]),	FP_REG(fp[20]), FP_REG(fp[21]), FP_REG(fp[22]), FP_REG(fp[23]),	FP_REG(fp[24]), FP_REG(fp[25]), FP_REG(fp[26]), FP_REG(fp[27]),	FP_REG(fp[28]), FP_REG(fp[29]), FP_REG(fp[30]), FP_REG(fp[31]),	PT_REG(	   pc)}; static unsigned long zero; /* * Get address of register REGNO in task TASK. */static unsigned long *get_reg_addr(struct task_struct * task, unsigned long regno){	unsigned long *addr; 	if (regno == 30) {		addr = &task_thread_info(task)->pcb.usp;	} else if (regno == 65) {		addr = &task_thread_info(task)->pcb.unique;	} else if (regno == 31 || regno > 65) {		zero = 0;		addr = &zero;	} else {		addr = task_stack_page(task) + regoff[regno];	}	return addr;} /* * Get contents of register REGNO in task TASK. */static unsigned longget_reg(struct task_struct * task, unsigned long regno){	/* Special hack for fpcr -- combine hardware and software bits.  */	if (regno == 63) {		unsigned long fpcr = *get_reg_addr(task, regno);		unsigned long swcr		  = task_thread_info(task)->ieee_state & IEEE_SW_MASK;		swcr = swcr_update_status(swcr, fpcr);		return fpcr | swcr;	}	return *get_reg_addr(task, regno);} static void alpha_elf_fpregs_get(struct task_struct *target,			 elf_fpreg_t *fpregs)  /* points to ELF_NFPREG entries */{	memcpy(fpregs, task_thread_info(target)->fp, sizeof(elf_fpregset_t));} static void alpha_elf_fpregs_set(struct task_struct *target,			 const elf_fpreg_t *fpregs,			 size_t nwords){	size_t n = min_t(size_t, nwords, ELF_NFPREG); 	memcpy(task_thread_info(target)->fp, fpregs, n * sizeof(elf_fpreg_t));} static void alpha_elf_gregs_set(struct task_struct *child,			const elf_greg_t *src,			size_t nwords){	struct pt_regs *pt = task_pt_regs(child);	struct thread_info *ti = task_thread_info(child);	struct switch_stack *sw = ((struct switch_stack *)pt) - 1; 	/* GPRs r0..r8 live in pt_regs */	if (nwords > 0)		pt->r0 = src[0];	if (nwords > 1)		pt->r1 = src[1];	if (nwords > 2)		pt->r2 = src[2];	if (nwords > 3)		pt->r3 = src[3];	if (nwords > 4)		pt->r4 = src[4];	if (nwords > 5)		pt->r5 = src[5];	if (nwords > 6)		pt->r6 = src[6];	if (nwords > 7)		pt->r7 = src[7];	if (nwords > 8)		pt->r8 = src[8]; 	/* r9..r15 live in switch_stack */	if (nwords > 9)		sw->r9 = src[9];	if (nwords > 10)		sw->r10 = src[10];	if (nwords > 11)		sw->r11 = src[11];	if (nwords > 12)		sw->r12 = src[12];	if (nwords > 13)		sw->r13 = src[13];	if (nwords > 14)		sw->r14 = src[14];	if (nwords > 15)		sw->r15 = src[15]; 	/* r16..r28 live in pt_regs */	if (nwords > 16)		pt->r16 = src[16];	if (nwords > 17)		pt->r17 = src[17];	if (nwords > 18)		pt->r18 = src[18];	if (nwords > 19)		pt->r19 = src[19];	if (nwords > 20)		pt->r20 = src[20];	if (nwords > 21)		pt->r21 = src[21];	if (nwords > 22)		pt->r22 = src[22];	if (nwords > 23)		pt->r23 = src[23];	if (nwords > 24)		pt->r24 = src[24];	if (nwords > 25)		pt->r25 = src[25];	if (nwords > 26)		pt->r26 = src[26];	if (nwords > 27)		pt->r27 = src[27];	if (nwords > 28)		pt->r28 = src[28]; 	/* gp, usp, pc, unique */	if (nwords > 29)		pt->gp = src[29]; 	if (nwords > 30) {		ti->pcb.usp = src[30];		/*		 * If someone ever does this to current (rare), keep the		 * hardware usp consistent.		 */		if (child == current)			wrusp(src[30]);	} 	if (nwords > 31)		pt->pc = src[31]; 	if (nwords > 32)		ti->pcb.unique = src[32]; /* * PTRACE_SETREGSET can be used at a syscall-entry stop to skip the * syscall by setting the syscall number to -1.  The seccomp/ptrace * selftests use this to synthesize errno returns. * * Alpha uses r19/a3 as the error flag, so a skipped syscall with a * small positive r0 and a clear r19 must be normalized to an error * return. */	if (pt->r1 == (unsigned long)-1 &&	    pt->r19 == 0 &&	    pt->r0 > 0 &&	    pt->r0 < MAX_ERRNO)		pt->r19 = 1;}  /* * Write contents of register REGNO in task TASK. */static intput_reg(struct task_struct *task, unsigned long regno, unsigned long data){	struct pt_regs *regs = task_pt_regs(task); 	if (regno == 63) {		task_thread_info(task)->ieee_state		  = ((task_thread_info(task)->ieee_state & ~IEEE_SW_MASK)		     | (data & IEEE_SW_MASK));		data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);	} 	*get_reg_addr(task, regno) = data; 	/*	 * Alpha historically exposes r0/v0 as the syscall number at a	 * syscall-entry stop.  The generic-entry conversion keeps the	 * mutable syscall number in regs->r1, so old ptrace users such	 * as strace that skip a syscall by poking r0 to -1 must also	 * update the internal shadow syscall number.	 *	 * Do not mirror other r0 writes.  strace later pokes r0 to the	 * injected return value, e.g. 42, while r1 must remain -1.	 */ 	if (regno == 0 && data == (unsigned long)-1) {		regs->r1 = data;		regs->r19 = 0;	} 	return 0;} static inline intread_int(struct task_struct *task, unsigned long addr, int * data){	int copied = access_process_vm(task, addr, data, sizeof(int),			FOLL_FORCE);	return (copied == sizeof(int)) ? 0 : -EIO;} static inline intwrite_int(struct task_struct *task, unsigned long addr, int data){	int copied = access_process_vm(task, addr, &data, sizeof(int),			FOLL_FORCE | FOLL_WRITE);	return (copied == sizeof(int)) ? 0 : -EIO;} /* * Set breakpoint. */intptrace_set_bpt(struct task_struct * child){	int displ, i, res, reg_b, nsaved = 0;	unsigned int insn, op_code;	unsigned long pc; 	pc  = get_reg(child, REG_PC);	res = read_int(child, pc, (int *) &insn);	if (res < 0)		return res; 	op_code = insn >> 26;	if (op_code >= 0x30) {		/*		 * It's a branch: instead of trying to figure out		 * whether the branch will be taken or not, we'll put		 * a breakpoint at either location.  This is simpler,		 * more reliable, and probably not a whole lot slower		 * than the alternative approach of emulating the		 * branch (emulation can be tricky for fp branches).		 */		displ = ((s32)(insn << 11)) >> 9;		task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;		if (displ)		/* guard against unoptimized code */			task_thread_info(child)->bpt_addr[nsaved++]			  = pc + 4 + displ;		DBG(DBG_BPT, ("execing branch\n"));	} else if (op_code == 0x1a) {		reg_b = (insn >> 16) & 0x1f;		task_thread_info(child)->bpt_addr[nsaved++] = get_reg(child, reg_b);		DBG(DBG_BPT, ("execing jump\n"));	} else {		task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;		DBG(DBG_BPT, ("execing normal insn\n"));	} 	/* install breakpoints: */	for (i = 0; i < nsaved; ++i) {		res = read_int(child, task_thread_info(child)->bpt_addr[i],			       (int *) &insn);		if (res < 0)			return res;		task_thread_info(child)->bpt_insn[i] = insn;		DBG(DBG_BPT, ("    -> next_pc=%lx\n",			      task_thread_info(child)->bpt_addr[i]));		res = write_int(child, task_thread_info(child)->bpt_addr[i],				BREAKINST);		if (res < 0)			return res;	}	task_thread_info(child)->bpt_nsaved = nsaved;	return 0;} /* * Ensure no single-step breakpoint is pending.  Returns non-zero * value if child was being single-stepped. */intptrace_cancel_bpt(struct task_struct * child){	int i, nsaved = task_thread_info(child)->bpt_nsaved; 	task_thread_info(child)->bpt_nsaved = 0; 	if (nsaved > 2) {		printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);		nsaved = 2;	} 	for (i = 0; i < nsaved; ++i) {		write_int(child, task_thread_info(child)->bpt_addr[i],			  task_thread_info(child)->bpt_insn[i]);	}	return (nsaved != 0);} void user_enable_single_step(struct task_struct *child){	/* Mark single stepping.  */	task_thread_info(child)->bpt_nsaved = -1;} void user_disable_single_step(struct task_struct *child){	ptrace_cancel_bpt(child);} /* * Called by kernel/ptrace.c when detaching.. * * Make sure the single step bit is not set. */void ptrace_disable(struct task_struct *child){ 	user_disable_single_step(child);} long arch_ptrace(struct task_struct *child, long request,		 unsigned long addr, unsigned long data){	unsigned long tmp;	size_t copied;	long ret; 	switch (request) {	/* When I and D space are separate, these will need to be fixed.  */	case PTRACE_PEEKTEXT: /* read word at location addr. */	case PTRACE_PEEKDATA:		copied = ptrace_access_vm(child, addr, &tmp, sizeof(tmp),				FOLL_FORCE);		ret = -EIO;		if (copied != sizeof(tmp))			break;				force_successful_syscall_return();		ret = tmp;		break; 	/* Read register number ADDR. */	case PTRACE_PEEKUSR:		force_successful_syscall_return();		ret = get_reg(child, addr);		DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret));		break; 	/* When I and D space are separate, this will have to be fixed.  */	case PTRACE_POKETEXT: /* write the word at location addr. */	case PTRACE_POKEDATA:		ret = generic_ptrace_pokedata(child, addr, data);		break; 	case PTRACE_POKEUSR: /* write the specified register */		DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));		ret = put_reg(child, addr, data);		break;	default:		ret = ptrace_request(child, request, addr, data);		break;	}	return ret;} asmlinkage unsigned long syscall_trace_enter(void){	struct pt_regs *regs = current_pt_regs(); 	if (test_thread_flag(TIF_SYSCALL_TRACE) &&		!ptrace_report_syscall_permit_entry(regs)) {		syscall_set_nr(current, regs, -1);		if (regs->r19 == 0 && regs->r0 == (unsigned long)-1)			syscall_set_return_value(current, regs, -ENOSYS, 0);		return -1UL;	} 	/*	 * Do the secure computing after ptrace; failures should be fast.	 * If this fails, seccomp may already have set up the return value	 * (e.g. SECCOMP_RET_ERRNO / TRACE).	 */	if (!seccomp_permit_syscall()) {		if (regs->r19 == 0 && regs->r0 == (unsigned long)-1)			syscall_set_return_value(current, regs, -ENOSYS, 0);		syscall_set_nr(current, regs, -1);		return -1UL;	} #ifdef CONFIG_AUDITSYSCALL	audit_syscall_entry(syscall_get_nr(current, regs),		regs->r16, regs->r17, regs->r18, regs->r19);

Lines 1–500 of 636.