ptrace.c (77bf4400319db9d2a8af6b00c2be6faa0f3d07cb) | ptrace.c (ba180fd437156f7fd8cfb2fdd021d949eeef08d6) |
---|---|
1/* 2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 1/* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 * Licensed under the GPL 4 */ 5 | 3 * Licensed under the GPL 4 */ 5 |
6#include "linux/sched.h" 7#include "linux/mm.h" 8#include "linux/errno.h" 9#include "linux/smp_lock.h" 10#include "linux/security.h" 11#include "linux/ptrace.h" | |
12#include "linux/audit.h" | 6#include "linux/audit.h" |
7#include "linux/ptrace.h" 8#include "linux/sched.h" 9#include "asm/uaccess.h" |
|
13#ifdef CONFIG_PROC_MM | 10#ifdef CONFIG_PROC_MM |
14#include "linux/proc_mm.h" | 11#include "proc_mm.h" |
15#endif | 12#endif |
16#include "asm/ptrace.h" 17#include "asm/uaccess.h" 18#include "kern_util.h" | |
19#include "skas_ptrace.h" | 13#include "skas_ptrace.h" |
20#include "sysdep/ptrace.h" 21#include "os.h" | |
22 23static inline void set_singlestepping(struct task_struct *child, int on) 24{ | 14 15static inline void set_singlestepping(struct task_struct *child, int on) 16{ |
25 if (on) 26 child->ptrace |= PT_DTRACE; 27 else 28 child->ptrace &= ~PT_DTRACE; 29 child->thread.singlestep_syscall = 0; | 17 if (on) 18 child->ptrace |= PT_DTRACE; 19 else 20 child->ptrace &= ~PT_DTRACE; 21 child->thread.singlestep_syscall = 0; |
30 31#ifdef SUBARCH_SET_SINGLESTEPPING | 22 23#ifdef SUBARCH_SET_SINGLESTEPPING |
32 SUBARCH_SET_SINGLESTEPPING(child, on); | 24 SUBARCH_SET_SINGLESTEPPING(child, on); |
33#endif 34} 35 36/* 37 * Called by kernel/ptrace.c when detaching.. 38 */ 39void ptrace_disable(struct task_struct *child) | 25#endif 26} 27 28/* 29 * Called by kernel/ptrace.c when detaching.. 30 */ 31void ptrace_disable(struct task_struct *child) |
40{ 41 set_singlestepping(child,0); | 32{ 33 set_singlestepping(child,0); |
42} 43 44extern int peek_user(struct task_struct * child, long addr, long data); 45extern int poke_user(struct task_struct * child, long addr, long data); 46 47long arch_ptrace(struct task_struct *child, long request, long addr, long data) 48{ 49 int i, ret; 50 unsigned long __user *p = (void __user *)(unsigned long)data; 51 52 switch (request) { | 34} 35 36extern int peek_user(struct task_struct * child, long addr, long data); 37extern int poke_user(struct task_struct * child, long addr, long data); 38 39long arch_ptrace(struct task_struct *child, long request, long addr, long data) 40{ 41 int i, ret; 42 unsigned long __user *p = (void __user *)(unsigned long)data; 43 44 switch (request) { |
53 /* when I and D space are separate, these will need to be fixed. */ 54 case PTRACE_PEEKTEXT: /* read word at location addr. */ | 45 /* read word at location addr. */ 46 case PTRACE_PEEKTEXT: |
55 case PTRACE_PEEKDATA: 56 ret = generic_ptrace_peekdata(child, addr, data); 57 break; 58 59 /* read the word at location addr in the USER area. */ | 47 case PTRACE_PEEKDATA: 48 ret = generic_ptrace_peekdata(child, addr, data); 49 break; 50 51 /* read the word at location addr in the USER area. */ |
60 case PTRACE_PEEKUSR: 61 ret = peek_user(child, addr, data); 62 break; | 52 case PTRACE_PEEKUSR: 53 ret = peek_user(child, addr, data); 54 break; |
63 | 55 |
64 /* when I and D space are separate, this will have to be fixed. */ 65 case PTRACE_POKETEXT: /* write the word at location addr. */ | 56 /* write the word at location addr. */ 57 case PTRACE_POKETEXT: |
66 case PTRACE_POKEDATA: 67 ret = generic_ptrace_pokedata(child, addr, data); 68 break; 69 | 58 case PTRACE_POKEDATA: 59 ret = generic_ptrace_pokedata(child, addr, data); 60 break; 61 |
70 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 71 ret = poke_user(child, addr, data); 72 break; | 62 /* write the word at location addr in the USER area */ 63 case PTRACE_POKEUSR: 64 ret = poke_user(child, addr, data); 65 break; |
73 | 66 |
74 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 75 case PTRACE_CONT: { /* restart after signal. */ | 67 /* continue and stop at next (return from) syscall */ 68 case PTRACE_SYSCALL: 69 /* restart after signal. */ 70 case PTRACE_CONT: { |
76 ret = -EIO; 77 if (!valid_signal(data)) 78 break; 79 | 71 ret = -EIO; 72 if (!valid_signal(data)) 73 break; 74 |
80 set_singlestepping(child, 0); 81 if (request == PTRACE_SYSCALL) { | 75 set_singlestepping(child, 0); 76 if (request == PTRACE_SYSCALL) |
82 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 77 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
83 } 84 else { 85 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 86 } | 78 else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
87 child->exit_code = data; 88 wake_up_process(child); 89 ret = 0; 90 break; 91 } 92 93/* | 79 child->exit_code = data; 80 wake_up_process(child); 81 ret = 0; 82 break; 83 } 84 85/* |
94 * make the child exit. Best I can do is send it a sigkill. 95 * perhaps it should be put in the status that it wants to | 86 * make the child exit. Best I can do is send it a sigkill. 87 * perhaps it should be put in the status that it wants to |
96 * exit. 97 */ 98 case PTRACE_KILL: { 99 ret = 0; 100 if (child->exit_state == EXIT_ZOMBIE) /* already dead */ 101 break; 102 | 88 * exit. 89 */ 90 case PTRACE_KILL: { 91 ret = 0; 92 if (child->exit_state == EXIT_ZOMBIE) /* already dead */ 93 break; 94 |
103 set_singlestepping(child, 0); | 95 set_singlestepping(child, 0); |
104 child->exit_code = SIGKILL; 105 wake_up_process(child); 106 break; 107 } 108 109 case PTRACE_SINGLESTEP: { /* set the trap flag. */ 110 ret = -EIO; 111 if (!valid_signal(data)) 112 break; 113 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 96 child->exit_code = SIGKILL; 97 wake_up_process(child); 98 break; 99 } 100 101 case PTRACE_SINGLESTEP: { /* set the trap flag. */ 102 ret = -EIO; 103 if (!valid_signal(data)) 104 break; 105 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
114 set_singlestepping(child, 1); | 106 set_singlestepping(child, 1); |
115 child->exit_code = data; 116 /* give it a chance to run. */ 117 wake_up_process(child); 118 ret = 0; 119 break; 120 } 121 122#ifdef PTRACE_GETREGS --- 52 unchanged lines hidden (view full) --- 175 break; 176 177 case PTRACE_SET_THREAD_AREA: 178 ret = ptrace_set_thread_area(child, addr, 179 (struct user_desc __user *) data); 180 break; 181 182 case PTRACE_FAULTINFO: { | 107 child->exit_code = data; 108 /* give it a chance to run. */ 109 wake_up_process(child); 110 ret = 0; 111 break; 112 } 113 114#ifdef PTRACE_GETREGS --- 52 unchanged lines hidden (view full) --- 167 break; 168 169 case PTRACE_SET_THREAD_AREA: 170 ret = ptrace_set_thread_area(child, addr, 171 (struct user_desc __user *) data); 172 break; 173 174 case PTRACE_FAULTINFO: { |
183 /* Take the info from thread->arch->faultinfo, | 175 /* 176 * Take the info from thread->arch->faultinfo, |
184 * but transfer max. sizeof(struct ptrace_faultinfo). 185 * On i386, ptrace_faultinfo is smaller! 186 */ 187 ret = copy_to_user(p, &child->thread.arch.faultinfo, 188 sizeof(struct ptrace_faultinfo)); | 177 * but transfer max. sizeof(struct ptrace_faultinfo). 178 * On i386, ptrace_faultinfo is smaller! 179 */ 180 ret = copy_to_user(p, &child->thread.arch.faultinfo, 181 sizeof(struct ptrace_faultinfo)); |
189 if(ret) | 182 if (ret) |
190 break; 191 break; 192 } 193 194#ifdef PTRACE_LDT 195 case PTRACE_LDT: { 196 struct ptrace_ldt ldt; 197 | 183 break; 184 break; 185 } 186 187#ifdef PTRACE_LDT 188 case PTRACE_LDT: { 189 struct ptrace_ldt ldt; 190 |
198 if(copy_from_user(&ldt, p, sizeof(ldt))){ | 191 if (copy_from_user(&ldt, p, sizeof(ldt))) { |
199 ret = -EIO; 200 break; 201 } 202 | 192 ret = -EIO; 193 break; 194 } 195 |
203 /* This one is confusing, so just punt and return -EIO for | 196 /* 197 * This one is confusing, so just punt and return -EIO for |
204 * now 205 */ 206 ret = -EIO; 207 break; 208 } 209#endif 210#ifdef CONFIG_PROC_MM 211 case PTRACE_SWITCH_MM: { 212 struct mm_struct *old = child->mm; 213 struct mm_struct *new = proc_mm_get_mm(data); 214 | 198 * now 199 */ 200 ret = -EIO; 201 break; 202 } 203#endif 204#ifdef CONFIG_PROC_MM 205 case PTRACE_SWITCH_MM: { 206 struct mm_struct *old = child->mm; 207 struct mm_struct *new = proc_mm_get_mm(data); 208 |
215 if(IS_ERR(new)){ | 209 if (IS_ERR(new)) { |
216 ret = PTR_ERR(new); 217 break; 218 } 219 220 atomic_inc(&new->mm_users); 221 child->mm = new; 222 child->active_mm = new; 223 mmput(old); 224 ret = 0; 225 break; 226 } 227#endif 228#ifdef PTRACE_ARCH_PRCTL | 210 ret = PTR_ERR(new); 211 break; 212 } 213 214 atomic_inc(&new->mm_users); 215 child->mm = new; 216 child->active_mm = new; 217 mmput(old); 218 ret = 0; 219 break; 220 } 221#endif 222#ifdef PTRACE_ARCH_PRCTL |
229 case PTRACE_ARCH_PRCTL: 230 /* XXX Calls ptrace on the host - needs some SMP thinking */ 231 ret = arch_prctl(child, data, (void *) addr); 232 break; | 223 case PTRACE_ARCH_PRCTL: 224 /* XXX Calls ptrace on the host - needs some SMP thinking */ 225 ret = arch_prctl(child, data, (void *) addr); 226 break; |
233#endif 234 default: 235 ret = ptrace_request(child, request, addr, data); 236 break; 237 } 238 239 return ret; 240} --- 9 unchanged lines hidden (view full) --- 250 251 /* User-mode eip? */ 252 info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL; 253 254 /* Send us the fakey SIGTRAP */ 255 force_sig_info(SIGTRAP, &info, tsk); 256} 257 | 227#endif 228 default: 229 ret = ptrace_request(child, request, addr, data); 230 break; 231 } 232 233 return ret; 234} --- 9 unchanged lines hidden (view full) --- 244 245 /* User-mode eip? */ 246 info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL; 247 248 /* Send us the fakey SIGTRAP */ 249 force_sig_info(SIGTRAP, &info, tsk); 250} 251 |
258/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and | 252/* 253 * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and |
259 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check 260 */ 261void syscall_trace(struct uml_pt_regs *regs, int entryexit) 262{ 263 int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; 264 int tracesysgood; 265 266 if (unlikely(current->audit_context)) { 267 if (!entryexit) 268 audit_syscall_entry(HOST_AUDIT_ARCH, 269 UPT_SYSCALL_NR(regs), 270 UPT_SYSCALL_ARG1(regs), 271 UPT_SYSCALL_ARG2(regs), 272 UPT_SYSCALL_ARG3(regs), 273 UPT_SYSCALL_ARG4(regs)); 274 else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), | 254 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check 255 */ 256void syscall_trace(struct uml_pt_regs *regs, int entryexit) 257{ 258 int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; 259 int tracesysgood; 260 261 if (unlikely(current->audit_context)) { 262 if (!entryexit) 263 audit_syscall_entry(HOST_AUDIT_ARCH, 264 UPT_SYSCALL_NR(regs), 265 UPT_SYSCALL_ARG1(regs), 266 UPT_SYSCALL_ARG2(regs), 267 UPT_SYSCALL_ARG3(regs), 268 UPT_SYSCALL_ARG4(regs)); 269 else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), |
275 UPT_SYSCALL_RET(regs)); | 270 UPT_SYSCALL_RET(regs)); |
276 } 277 278 /* Fake a debug trap */ 279 if (is_singlestep) 280 send_sigtrap(current, regs, 0); 281 282 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 283 return; 284 285 if (!(current->ptrace & PT_PTRACED)) 286 return; 287 | 271 } 272 273 /* Fake a debug trap */ 274 if (is_singlestep) 275 send_sigtrap(current, regs, 0); 276 277 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 278 return; 279 280 if (!(current->ptrace & PT_PTRACED)) 281 return; 282 |
288 /* the 0x80 provides a way for the tracing parent to distinguish 289 between a syscall stop and SIGTRAP delivery */ | 283 /* 284 * the 0x80 provides a way for the tracing parent to distinguish 285 * between a syscall stop and SIGTRAP delivery 286 */ |
290 tracesysgood = (current->ptrace & PT_TRACESYSGOOD); 291 ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); 292 293 if (entryexit) /* force do_signal() --> is_syscall() */ 294 set_thread_flag(TIF_SIGPENDING); 295 | 287 tracesysgood = (current->ptrace & PT_TRACESYSGOOD); 288 ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); 289 290 if (entryexit) /* force do_signal() --> is_syscall() */ 291 set_thread_flag(TIF_SIGPENDING); 292 |
296 /* this isn't the same as continuing with a signal, but it will do | 293 /* 294 * this isn't the same as continuing with a signal, but it will do |
297 * for normal use. strace only continues with a signal if the 298 * stopping signal is not SIGTRAP. -brl 299 */ 300 if (current->exit_code) { 301 send_sig(current->exit_code, current, 1); 302 current->exit_code = 0; 303 } 304} | 295 * for normal use. strace only continues with a signal if the 296 * stopping signal is not SIGTRAP. -brl 297 */ 298 if (current->exit_code) { 299 send_sig(current->exit_code, current, 1); 300 current->exit_code = 0; 301 } 302} |