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