Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
0004  */
0005 
0006 #include <linux/audit.h>
0007 #include <linux/ptrace.h>
0008 #include <linux/sched.h>
0009 #include <linux/uaccess.h>
0010 #include <asm/ptrace-abi.h>
0011 
0012 void user_enable_single_step(struct task_struct *child)
0013 {
0014     set_tsk_thread_flag(child, TIF_SINGLESTEP);
0015     child->thread.singlestep_syscall = 0;
0016 
0017 #ifdef SUBARCH_SET_SINGLESTEPPING
0018     SUBARCH_SET_SINGLESTEPPING(child, 1);
0019 #endif
0020 }
0021 
0022 void user_disable_single_step(struct task_struct *child)
0023 {
0024     clear_tsk_thread_flag(child, TIF_SINGLESTEP);
0025     child->thread.singlestep_syscall = 0;
0026 
0027 #ifdef SUBARCH_SET_SINGLESTEPPING
0028     SUBARCH_SET_SINGLESTEPPING(child, 0);
0029 #endif
0030 }
0031 
0032 /*
0033  * Called by kernel/ptrace.c when detaching..
0034  */
0035 void ptrace_disable(struct task_struct *child)
0036 {
0037     user_disable_single_step(child);
0038 }
0039 
0040 extern int peek_user(struct task_struct * child, long addr, long data);
0041 extern int poke_user(struct task_struct * child, long addr, long data);
0042 
0043 long arch_ptrace(struct task_struct *child, long request,
0044          unsigned long addr, unsigned long data)
0045 {
0046     int i, ret;
0047     unsigned long __user *p = (void __user *)data;
0048     void __user *vp = p;
0049 
0050     switch (request) {
0051     /* read the word at location addr in the USER area. */
0052     case PTRACE_PEEKUSR:
0053         ret = peek_user(child, addr, data);
0054         break;
0055 
0056     /* write the word at location addr in the USER area */
0057     case PTRACE_POKEUSR:
0058         ret = poke_user(child, addr, data);
0059         break;
0060 
0061     case PTRACE_SYSEMU:
0062     case PTRACE_SYSEMU_SINGLESTEP:
0063         ret = -EIO;
0064         break;
0065 
0066 #ifdef PTRACE_GETREGS
0067     case PTRACE_GETREGS: { /* Get all gp regs from the child. */
0068         if (!access_ok(p, MAX_REG_OFFSET)) {
0069             ret = -EIO;
0070             break;
0071         }
0072         for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
0073             __put_user(getreg(child, i), p);
0074             p++;
0075         }
0076         ret = 0;
0077         break;
0078     }
0079 #endif
0080 #ifdef PTRACE_SETREGS
0081     case PTRACE_SETREGS: { /* Set all gp regs in the child. */
0082         unsigned long tmp = 0;
0083         if (!access_ok(p, MAX_REG_OFFSET)) {
0084             ret = -EIO;
0085             break;
0086         }
0087         for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
0088             __get_user(tmp, p);
0089             putreg(child, i, tmp);
0090             p++;
0091         }
0092         ret = 0;
0093         break;
0094     }
0095 #endif
0096     case PTRACE_GET_THREAD_AREA:
0097         ret = ptrace_get_thread_area(child, addr, vp);
0098         break;
0099 
0100     case PTRACE_SET_THREAD_AREA:
0101         ret = ptrace_set_thread_area(child, addr, vp);
0102         break;
0103 
0104     default:
0105         ret = ptrace_request(child, request, addr, data);
0106         if (ret == -EIO)
0107             ret = subarch_ptrace(child, request, addr, data);
0108         break;
0109     }
0110 
0111     return ret;
0112 }
0113 
0114 static void send_sigtrap(struct uml_pt_regs *regs, int error_code)
0115 {
0116     /* Send us the fake SIGTRAP */
0117     force_sig_fault(SIGTRAP, TRAP_BRKPT,
0118             /* User-mode eip? */
0119             UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL);
0120 }
0121 
0122 /*
0123  * XXX Check TIF_SINGLESTEP for singlestepping check and
0124  * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
0125  */
0126 int syscall_trace_enter(struct pt_regs *regs)
0127 {
0128     audit_syscall_entry(UPT_SYSCALL_NR(&regs->regs),
0129                 UPT_SYSCALL_ARG1(&regs->regs),
0130                 UPT_SYSCALL_ARG2(&regs->regs),
0131                 UPT_SYSCALL_ARG3(&regs->regs),
0132                 UPT_SYSCALL_ARG4(&regs->regs));
0133 
0134     if (!test_thread_flag(TIF_SYSCALL_TRACE))
0135         return 0;
0136 
0137     return ptrace_report_syscall_entry(regs);
0138 }
0139 
0140 void syscall_trace_leave(struct pt_regs *regs)
0141 {
0142     int ptraced = current->ptrace;
0143 
0144     audit_syscall_exit(regs);
0145 
0146     /* Fake a debug trap */
0147     if (test_thread_flag(TIF_SINGLESTEP))
0148         send_sigtrap(&regs->regs, 0);
0149 
0150     if (!test_thread_flag(TIF_SYSCALL_TRACE))
0151         return;
0152 
0153     ptrace_report_syscall_exit(regs, 0);
0154     /* force do_signal() --> is_syscall() */
0155     if (ptraced & PT_PTRACED)
0156         set_thread_flag(TIF_SIGPENDING);
0157 }