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