From acc7088569c8eef04eeed0eff51d23bb5bcff964 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Tue, 17 Sep 2002 11:50:35 -0400 Subject: Factor out common ptrace code and PTRACE_SETOPTIONS Support PTRACE_O_TRACESYSGOOD on all platforms --- kernel/ptrace.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'kernel') diff --git a/kernel/ptrace.c b/kernel/ptrace.c index cc7a76bb65b7..ab3aa39a38cf 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -248,3 +248,35 @@ int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int } return copied; } + +int ptrace_setoptions(struct task_struct *child, long data) +{ + if (data & PTRACE_O_TRACESYSGOOD) + child->ptrace |= PT_TRACESYSGOOD; + else + child->ptrace &= ~PT_TRACESYSGOOD; + + if ((data & PTRACE_O_TRACESYSGOOD) != data) + return -EINVAL; + + return 0; +} + +int ptrace_request(struct task_struct *child, long request, + long addr, long data) +{ + int ret = -EIO; + + switch (request) { +#ifdef PTRACE_OLDSETOPTIONS + case PTRACE_OLDSETOPTIONS: +#endif + case PTRACE_SETOPTIONS: + ret = ptrace_setoptions(child, data); + break; + default: + break; + } + + return ret; +} -- cgit v1.2.3 From a0691b116f6a4473f0fa264210ab9b95771a2b46 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Tue, 17 Sep 2002 12:21:24 -0400 Subject: Add new ptrace event tracing mechanism --- fs/binfmt_aout.c | 8 ++++++-- fs/binfmt_elf.c | 8 ++++++-- include/linux/ptrace.h | 12 ++++++++++++ include/linux/sched.h | 6 ++++++ kernel/fork.c | 29 +++++++++++++++++++++++++++++ kernel/ptrace.c | 41 +++++++++++++++++++++++++++++++++++++++-- 6 files changed, 98 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index f30aa6348608..2e37ff44188d 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -425,8 +425,12 @@ beyond_if: regs->gp = ex.a_gpvalue; #endif start_thread(regs, ex.a_entry, current->mm->start_stack); - if (current->ptrace & PT_PTRACED) - send_sig(SIGTRAP, current, 0); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } return 0; } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index aa71b1c83cd2..45a5f924de24 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -792,8 +792,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) #endif start_thread(regs, elf_entry, bprm->p); - if (current->ptrace & PT_PTRACED) - send_sig(SIGTRAP, current, 0); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } retval = 0; out: return retval; diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 8d4f8dcefbab..c6de3a4ea70a 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -25,9 +25,20 @@ /* 0x4200-0x4300 are reserved for architecture-independent additions. */ #define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 /* options set using PTRACE_SETOPTIONS */ #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 #include @@ -39,6 +50,7 @@ extern int ptrace_detach(struct task_struct *, unsigned int); extern void ptrace_disable(struct task_struct *); 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 void ptrace_notify(int exit_code); extern void __ptrace_link(struct task_struct *child, struct task_struct *new_parent); extern void __ptrace_unlink(struct task_struct *child); diff --git a/include/linux/sched.h b/include/linux/sched.h index 26a7388f3b56..86c24d631b73 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -397,6 +397,8 @@ struct task_struct { /* journalling filesystem info */ void *journal_info; struct dentry *proc_dentry; + + unsigned long ptrace_message; }; 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) #define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ #define PT_TRACESYSGOOD 0x00000004 #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 diff --git a/kernel/fork.c b/kernel/fork.c index b95e5aa0e0de..81e9f2608bef 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -923,6 +923,22 @@ bad_fork_free: 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. * @@ -936,6 +952,13 @@ struct task_struct *do_fork(unsigned long clone_flags, int *user_tid) { 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); if (!IS_ERR(p)) { @@ -951,6 +974,12 @@ struct task_struct *do_fork(unsigned long clone_flags, wake_up_forked_process(p); /* do this last */ ++total_forks; + + if (unlikely (trace)) { + current->ptrace_message = (unsigned long) p->pid; + ptrace_notify ((trace << 8) | SIGTRAP); + } + if (clone_flags & CLONE_VFORK) wait_for_completion(&vfork); else diff --git a/kernel/ptrace.c b/kernel/ptrace.c index ab3aa39a38cf..a2611977e53b 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -249,14 +249,37 @@ int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int 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) child->ptrace |= PT_TRACESYSGOOD; else 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 0; @@ -274,9 +297,23 @@ int ptrace_request(struct task_struct *child, long request, case PTRACE_SETOPTIONS: ret = ptrace_setoptions(child, data); break; + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message, (unsigned long *) data); + break; default: break; } 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(); +} -- cgit v1.2.3