ptrace.c (3586B)
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 12void user_enable_single_step(struct task_struct *child) 13{ 14 set_tsk_thread_flag(child, TIF_SINGLESTEP); 15 child->thread.singlestep_syscall = 0; 16 17#ifdef SUBARCH_SET_SINGLESTEPPING 18 SUBARCH_SET_SINGLESTEPPING(child, 1); 19#endif 20} 21 22void user_disable_single_step(struct task_struct *child) 23{ 24 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 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 */ 35void ptrace_disable(struct task_struct *child) 36{ 37 user_disable_single_step(child); 38} 39 40extern int peek_user(struct task_struct * child, long addr, long data); 41extern int poke_user(struct task_struct * child, long addr, long data); 42 43long 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 114static 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 TIF_SINGLESTEP for singlestepping check and 124 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check 125 */ 126int 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 140void 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 (test_thread_flag(TIF_SINGLESTEP)) 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}