1 /* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6 #include <linux/audit.h> 7 #include <linux/ptrace.h> 8 #include <linux/sched.h> 9 #include <linux/tracehook.h> 10 #include <linux/uaccess.h> 11 #include <asm/ptrace-abi.h> 12 13 void user_enable_single_step(struct task_struct *child) 14 { 15 child->ptrace |= PT_DTRACE; 16 child->thread.singlestep_syscall = 0; 17 18 #ifdef SUBARCH_SET_SINGLESTEPPING 19 SUBARCH_SET_SINGLESTEPPING(child, 1); 20 #endif 21 } 22 23 void user_disable_single_step(struct task_struct *child) 24 { 25 child->ptrace &= ~PT_DTRACE; 26 child->thread.singlestep_syscall = 0; 27 28 #ifdef SUBARCH_SET_SINGLESTEPPING 29 SUBARCH_SET_SINGLESTEPPING(child, 0); 30 #endif 31 } 32 33 /* 34 * Called by kernel/ptrace.c when detaching.. 35 */ 36 void ptrace_disable(struct task_struct *child) 37 { 38 user_disable_single_step(child); 39 } 40 41 extern int peek_user(struct task_struct * child, long addr, long data); 42 extern int poke_user(struct task_struct * child, long addr, long data); 43 44 long arch_ptrace(struct task_struct *child, long request, 45 unsigned long addr, unsigned long data) 46 { 47 int i, ret; 48 unsigned long __user *p = (void __user *)data; 49 void __user *vp = p; 50 51 switch (request) { 52 /* read the word at location addr in the USER area. */ 53 case PTRACE_PEEKUSR: 54 ret = peek_user(child, addr, data); 55 break; 56 57 /* write the word at location addr in the USER area */ 58 case PTRACE_POKEUSR: 59 ret = poke_user(child, addr, data); 60 break; 61 62 case PTRACE_SYSEMU: 63 case PTRACE_SYSEMU_SINGLESTEP: 64 ret = -EIO; 65 break; 66 67 #ifdef PTRACE_GETREGS 68 case PTRACE_GETREGS: { /* Get all gp regs from the child. */ 69 if (!access_ok(p, MAX_REG_OFFSET)) { 70 ret = -EIO; 71 break; 72 } 73 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { 74 __put_user(getreg(child, i), p); 75 p++; 76 } 77 ret = 0; 78 break; 79 } 80 #endif 81 #ifdef PTRACE_SETREGS 82 case PTRACE_SETREGS: { /* Set all gp regs in the child. */ 83 unsigned long tmp = 0; 84 if (!access_ok(p, MAX_REG_OFFSET)) { 85 ret = -EIO; 86 break; 87 } 88 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { 89 __get_user(tmp, p); 90 putreg(child, i, tmp); 91 p++; 92 } 93 ret = 0; 94 break; 95 } 96 #endif 97 case PTRACE_GET_THREAD_AREA: 98 ret = ptrace_get_thread_area(child, addr, vp); 99 break; 100 101 case PTRACE_SET_THREAD_AREA: 102 ret = ptrace_set_thread_area(child, addr, vp); 103 break; 104 105 default: 106 ret = ptrace_request(child, request, addr, data); 107 if (ret == -EIO) 108 ret = subarch_ptrace(child, request, addr, data); 109 break; 110 } 111 112 return ret; 113 } 114 115 static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, 116 int error_code) 117 { 118 /* Send us the fake SIGTRAP */ 119 force_sig_fault(SIGTRAP, TRAP_BRKPT, 120 /* User-mode eip? */ 121 UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL, tsk); 122 } 123 124 /* 125 * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and 126 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check 127 */ 128 int syscall_trace_enter(struct pt_regs *regs) 129 { 130 audit_syscall_entry(UPT_SYSCALL_NR(®s->regs), 131 UPT_SYSCALL_ARG1(®s->regs), 132 UPT_SYSCALL_ARG2(®s->regs), 133 UPT_SYSCALL_ARG3(®s->regs), 134 UPT_SYSCALL_ARG4(®s->regs)); 135 136 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 137 return 0; 138 139 return tracehook_report_syscall_entry(regs); 140 } 141 142 void syscall_trace_leave(struct pt_regs *regs) 143 { 144 int ptraced = current->ptrace; 145 146 audit_syscall_exit(regs); 147 148 /* Fake a debug trap */ 149 if (ptraced & PT_DTRACE) 150 send_sigtrap(current, ®s->regs, 0); 151 152 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 153 return; 154 155 tracehook_report_syscall_exit(regs, 0); 156 /* force do_signal() --> is_syscall() */ 157 if (ptraced & PT_PTRACED) 158 set_thread_flag(TIF_SIGPENDING); 159 } 160