Commit a0691b11 authored by Daniel Jacobowitz's avatar Daniel Jacobowitz

Add new ptrace event tracing mechanism

parent e6f9f840
...@@ -425,8 +425,12 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -425,8 +425,12 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
regs->gp = ex.a_gpvalue; regs->gp = ex.a_gpvalue;
#endif #endif
start_thread(regs, ex.a_entry, current->mm->start_stack); start_thread(regs, ex.a_entry, current->mm->start_stack);
if (current->ptrace & PT_PTRACED) if (unlikely(current->ptrace & PT_PTRACED)) {
send_sig(SIGTRAP, current, 0); if (current->ptrace & PT_TRACE_EXEC)
ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
else
send_sig(SIGTRAP, current, 0);
}
return 0; return 0;
} }
......
...@@ -792,8 +792,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -792,8 +792,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
#endif #endif
start_thread(regs, elf_entry, bprm->p); start_thread(regs, elf_entry, bprm->p);
if (current->ptrace & PT_PTRACED) if (unlikely(current->ptrace & PT_PTRACED)) {
send_sig(SIGTRAP, current, 0); if (current->ptrace & PT_TRACE_EXEC)
ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
else
send_sig(SIGTRAP, current, 0);
}
retval = 0; retval = 0;
out: out:
return retval; return retval;
......
...@@ -25,9 +25,20 @@ ...@@ -25,9 +25,20 @@
/* 0x4200-0x4300 are reserved for architecture-independent additions. */ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
#define PTRACE_SETOPTIONS 0x4200 #define PTRACE_SETOPTIONS 0x4200
#define PTRACE_GETEVENTMSG 0x4201
/* options set using PTRACE_SETOPTIONS */ /* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001 #define PTRACE_O_TRACESYSGOOD 0x00000001
#define PTRACE_O_TRACEFORK 0x00000002
#define PTRACE_O_TRACEVFORK 0x00000004
#define PTRACE_O_TRACECLONE 0x00000008
#define PTRACE_O_TRACEEXEC 0x00000010
/* Wait extended result codes for the above trace options. */
#define PTRACE_EVENT_FORK 1
#define PTRACE_EVENT_VFORK 2
#define PTRACE_EVENT_CLONE 3
#define PTRACE_EVENT_EXEC 4
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -39,6 +50,7 @@ extern int ptrace_detach(struct task_struct *, unsigned int); ...@@ -39,6 +50,7 @@ extern int ptrace_detach(struct task_struct *, unsigned int);
extern void ptrace_disable(struct task_struct *); extern void ptrace_disable(struct task_struct *);
extern int ptrace_check_attach(struct task_struct *task, int kill); extern int ptrace_check_attach(struct task_struct *task, int kill);
extern int ptrace_request(struct task_struct *child, long request, long addr, long data); extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
extern void ptrace_notify(int exit_code);
extern void __ptrace_link(struct task_struct *child, extern void __ptrace_link(struct task_struct *child,
struct task_struct *new_parent); struct task_struct *new_parent);
extern void __ptrace_unlink(struct task_struct *child); extern void __ptrace_unlink(struct task_struct *child);
......
...@@ -397,6 +397,8 @@ struct task_struct { ...@@ -397,6 +397,8 @@ struct task_struct {
/* journalling filesystem info */ /* journalling filesystem info */
void *journal_info; void *journal_info;
struct dentry *proc_dentry; struct dentry *proc_dentry;
unsigned long ptrace_message;
}; };
extern void __put_task_struct(struct task_struct *tsk); extern void __put_task_struct(struct task_struct *tsk);
...@@ -435,6 +437,10 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) ...@@ -435,6 +437,10 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ #define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */
#define PT_TRACESYSGOOD 0x00000004 #define PT_TRACESYSGOOD 0x00000004
#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */ #define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */
#define PT_TRACE_FORK 0x00000010
#define PT_TRACE_VFORK 0x00000020
#define PT_TRACE_CLONE 0x00000040
#define PT_TRACE_EXEC 0x00000080
/* /*
* Limit the stack by to some sane default: root can always * Limit the stack by to some sane default: root can always
......
...@@ -923,6 +923,22 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -923,6 +923,22 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto fork_out; goto fork_out;
} }
static inline int fork_traceflag (unsigned clone_flags)
{
if (clone_flags & (CLONE_UNTRACED | CLONE_IDLETASK))
return 0;
else if (clone_flags & CLONE_VFORK) {
if (current->ptrace & PT_TRACE_VFORK)
return PTRACE_EVENT_VFORK;
} else if ((clone_flags & CSIGNAL) != SIGCHLD) {
if (current->ptrace & PT_TRACE_CLONE)
return PTRACE_EVENT_CLONE;
} else if (current->ptrace & PT_TRACE_FORK)
return PTRACE_EVENT_FORK;
return 0;
}
/* /*
* Ok, this is the main fork-routine. * Ok, this is the main fork-routine.
* *
...@@ -936,6 +952,13 @@ struct task_struct *do_fork(unsigned long clone_flags, ...@@ -936,6 +952,13 @@ struct task_struct *do_fork(unsigned long clone_flags,
int *user_tid) int *user_tid)
{ {
struct task_struct *p; struct task_struct *p;
int trace = 0;
if (unlikely(current->ptrace)) {
trace = fork_traceflag (clone_flags);
if (trace)
clone_flags |= CLONE_PTRACE;
}
p = copy_process(clone_flags, stack_start, regs, stack_size, user_tid); p = copy_process(clone_flags, stack_start, regs, stack_size, user_tid);
if (!IS_ERR(p)) { if (!IS_ERR(p)) {
...@@ -951,6 +974,12 @@ struct task_struct *do_fork(unsigned long clone_flags, ...@@ -951,6 +974,12 @@ struct task_struct *do_fork(unsigned long clone_flags,
wake_up_forked_process(p); /* do this last */ wake_up_forked_process(p); /* do this last */
++total_forks; ++total_forks;
if (unlikely (trace)) {
current->ptrace_message = (unsigned long) p->pid;
ptrace_notify ((trace << 8) | SIGTRAP);
}
if (clone_flags & CLONE_VFORK) if (clone_flags & CLONE_VFORK)
wait_for_completion(&vfork); wait_for_completion(&vfork);
else else
......
...@@ -249,14 +249,37 @@ int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int ...@@ -249,14 +249,37 @@ int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int
return copied; return copied;
} }
int ptrace_setoptions(struct task_struct *child, long data) static int ptrace_setoptions(struct task_struct *child, long data)
{ {
if (data & PTRACE_O_TRACESYSGOOD) if (data & PTRACE_O_TRACESYSGOOD)
child->ptrace |= PT_TRACESYSGOOD; child->ptrace |= PT_TRACESYSGOOD;
else else
child->ptrace &= ~PT_TRACESYSGOOD; child->ptrace &= ~PT_TRACESYSGOOD;
if ((data & PTRACE_O_TRACESYSGOOD) != data) if (data & PTRACE_O_TRACEFORK)
child->ptrace |= PT_TRACE_FORK;
else
child->ptrace &= ~PT_TRACE_FORK;
if (data & PTRACE_O_TRACEVFORK)
child->ptrace |= PT_TRACE_VFORK;
else
child->ptrace &= ~PT_TRACE_VFORK;
if (data & PTRACE_O_TRACECLONE)
child->ptrace |= PT_TRACE_CLONE;
else
child->ptrace &= ~PT_TRACE_CLONE;
if (data & PTRACE_O_TRACEEXEC)
child->ptrace |= PT_TRACE_EXEC;
else
child->ptrace &= ~PT_TRACE_EXEC;
if ((data & (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK
| PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE
| PTRACE_O_TRACEEXEC))
!= data)
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -274,9 +297,23 @@ int ptrace_request(struct task_struct *child, long request, ...@@ -274,9 +297,23 @@ int ptrace_request(struct task_struct *child, long request,
case PTRACE_SETOPTIONS: case PTRACE_SETOPTIONS:
ret = ptrace_setoptions(child, data); ret = ptrace_setoptions(child, data);
break; break;
case PTRACE_GETEVENTMSG:
ret = put_user(child->ptrace_message, (unsigned long *) data);
break;
default: default:
break; break;
} }
return ret; return ret;
} }
void ptrace_notify(int exit_code)
{
BUG_ON (!(current->ptrace & PT_PTRACED));
/* Let the debugger run. */
current->exit_code = exit_code;
set_current_state(TASK_STOPPED);
notify_parent(current, SIGCHLD);
schedule();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment