Contributors: 12
Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
Jeff Dike |
344 |
59.31% |
13 |
39.39% |
Al Viro |
71 |
12.24% |
3 |
9.09% |
Paolo 'Blaisorblade' Giarrusso |
63 |
10.86% |
3 |
9.09% |
Christoph Hellwig |
24 |
4.14% |
2 |
6.06% |
Bodo Stroesser |
24 |
4.14% |
1 |
3.03% |
Eric W. Biedermann |
21 |
3.62% |
3 |
9.09% |
Renzo Davoli |
12 |
2.07% |
1 |
3.03% |
Namhyung Kim |
10 |
1.72% |
2 |
6.06% |
Richard Weinberger |
7 |
1.21% |
2 |
6.06% |
Alex Dewar |
2 |
0.34% |
1 |
3.03% |
Linus Torvalds |
1 |
0.17% |
1 |
3.03% |
Américo Wang |
1 |
0.17% |
1 |
3.03% |
Total |
580 |
|
33 |
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/
#include <linux/audit.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/ptrace-abi.h>
void user_enable_single_step(struct task_struct *child)
{
set_tsk_thread_flag(child, TIF_SINGLESTEP);
#ifdef SUBARCH_SET_SINGLESTEPPING
SUBARCH_SET_SINGLESTEPPING(child, 1);
#endif
}
void user_disable_single_step(struct task_struct *child)
{
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
#ifdef SUBARCH_SET_SINGLESTEPPING
SUBARCH_SET_SINGLESTEPPING(child, 0);
#endif
}
/*
* Called by kernel/ptrace.c when detaching..
*/
void ptrace_disable(struct task_struct *child)
{
user_disable_single_step(child);
}
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
int i, ret;
unsigned long __user *p = (void __user *)data;
void __user *vp = p;
switch (request) {
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR:
ret = peek_user(child, addr, data);
break;
/* write the word at location addr in the USER area */
case PTRACE_POKEUSR:
ret = poke_user(child, addr, data);
break;
case PTRACE_SYSEMU:
case PTRACE_SYSEMU_SINGLESTEP:
ret = -EIO;
break;
#ifdef PTRACE_GETREGS
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
if (!access_ok(p, MAX_REG_OFFSET)) {
ret = -EIO;
break;
}
for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
__put_user(getreg(child, i), p);
p++;
}
ret = 0;
break;
}
#endif
#ifdef PTRACE_SETREGS
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
unsigned long tmp = 0;
if (!access_ok(p, MAX_REG_OFFSET)) {
ret = -EIO;
break;
}
for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
__get_user(tmp, p);
putreg(child, i, tmp);
p++;
}
ret = 0;
break;
}
#endif
case PTRACE_GET_THREAD_AREA:
ret = ptrace_get_thread_area(child, addr, vp);
break;
case PTRACE_SET_THREAD_AREA:
ret = ptrace_set_thread_area(child, addr, vp);
break;
default:
ret = ptrace_request(child, request, addr, data);
if (ret == -EIO)
ret = subarch_ptrace(child, request, addr, data);
break;
}
return ret;
}
static void send_sigtrap(struct uml_pt_regs *regs, int error_code)
{
/* Send us the fake SIGTRAP */
force_sig_fault(SIGTRAP, TRAP_BRKPT,
/* User-mode eip? */
UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL);
}
/*
* XXX Check TIF_SINGLESTEP for singlestepping check and
* PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
*/
int syscall_trace_enter(struct pt_regs *regs)
{
audit_syscall_entry(UPT_SYSCALL_NR(®s->regs),
UPT_SYSCALL_ARG1(®s->regs),
UPT_SYSCALL_ARG2(®s->regs),
UPT_SYSCALL_ARG3(®s->regs),
UPT_SYSCALL_ARG4(®s->regs));
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return 0;
return ptrace_report_syscall_entry(regs);
}
void syscall_trace_leave(struct pt_regs *regs)
{
int ptraced = current->ptrace;
audit_syscall_exit(regs);
/* Fake a debug trap */
if (test_thread_flag(TIF_SINGLESTEP))
send_sigtrap(®s->regs, 0);
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
ptrace_report_syscall_exit(regs, 0);
/* force do_signal() --> is_syscall() */
if (ptraced & PT_PTRACED)
set_thread_flag(TIF_SIGPENDING);
}