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