On top of http://people.redhat.com/roland/utrace/2.6-current/utrace-ptrace.patch
We need a starting point: a patch which at least partly works. To discuss the actual changes, to have the ability to test things, etc. But, due to discussed task_ptrace() problems, the patch above can't work in any way. So I just removed the old code for now. With this patch the kernel boots, but ptrace is not useable: the kernel crashes very quickly during 'make check' (ptrace-tests). It crashes on "random" test, usually 3-5 is enough. I spent some time trying to investigate, but then decided it doesn't make sense _now_. I suspect, the partly-detach logic is the main offender. We will see. --- include/linux/ptrace.h | 41 ----------- include/linux/tracehook.h | 40 ----------- kernel/ptrace.c | 163 ---------------------------------------------- kernel/utrace.c | 15 ---- 4 files changed, 2 insertions(+), 257 deletions(-) --- PU/include/linux/ptrace.h~01_REMOVE_OLD_CODE 2009-08-11 16:54:21.000000000 +0200 +++ PU/include/linux/ptrace.h 2009-08-13 15:19:18.000000000 +0200 @@ -120,7 +120,6 @@ static inline void ptrace_unlink(struct int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data); int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data); -#ifndef CONFIG_UTRACE_PTRACE /** * task_ptrace - return %PT_* flags that apply to a task * @task: pointer to &task_struct in question @@ -132,48 +131,8 @@ static inline int task_ptrace(struct tas return task->ptrace; } -/** - * ptrace_event - possibly stop for a ptrace event notification - * @mask: %PT_* bit to check in @current->ptrace - * @event: %PTRACE_EVENT_* value to report if @mask is set - * @message: value for %PTRACE_GETEVENTMSG to return - * - * This checks the @mask bit to see if ptrace wants stops for this event. - * If so we stop, reporting @event and @message to the ptrace parent. - * - * Returns nonzero if we did a ptrace notification, zero if not. - * - * Called without locks. - */ -static inline int ptrace_event(int mask, int event, unsigned long message) -{ - if (mask && likely(!(current->ptrace & mask))) - return 0; - current->ptrace_message = message; - ptrace_notify((event << 8) | SIGTRAP); - return 1; -} - -static inline void ptrace_utrace_exit(struct task_struct *task) -{ -} - -#else /* CONFIG_UTRACE_PTRACE */ - -static inline int task_ptrace(struct task_struct *task) -{ - return 0; -} - -static inline int ptrace_event(int mask, int event, unsigned long message) -{ - return 0; -} - extern void ptrace_utrace_exit(struct task_struct *); -#endif /* !CONFIG_UTRACE_PTRACE */ - /** * ptrace_init_task - initialize ptrace state for a new child * @child: new child task --- PU/include/linux/tracehook.h~01_REMOVE_OLD_CODE 2009-08-11 16:54:21.000000000 +0200 +++ PU/include/linux/tracehook.h 2009-08-13 15:50:27.000000000 +0200 @@ -69,29 +69,6 @@ static inline int tracehook_expect_break return (task_ptrace(task) & PT_PTRACED) != 0; } -/* - * ptrace report for syscall entry and exit looks identical. - */ -static inline void ptrace_report_syscall(struct pt_regs *regs) -{ - int ptrace = task_ptrace(current); - - if (!(ptrace & PT_PTRACED)) - return; - - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } -} - /** * tracehook_report_syscall_entry - task is about to attempt a system call * @regs: user register state of current task @@ -117,7 +94,6 @@ static inline __must_check int tracehook if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) && utrace_report_syscall_entry(regs)) return 1; - ptrace_report_syscall(regs); return 0; } @@ -142,7 +118,6 @@ static inline void tracehook_report_sysc { if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) utrace_report_syscall_exit(regs); - ptrace_report_syscall(regs); } /** @@ -156,7 +131,7 @@ static inline void tracehook_report_sysc static inline int tracehook_unsafe_exec(struct task_struct *task) { int unsafe = 0; - int ptrace = task->ptrace; + int ptrace = task_ptrace(task); if (ptrace & PT_PTRACED) { if (ptrace & PT_PTRACE_CAP) unsafe |= LSM_UNSAFE_PTRACE_CAP; @@ -179,7 +154,7 @@ static inline int tracehook_unsafe_exec( */ static inline struct task_struct *tracehook_tracer_task(struct task_struct *tsk) { - if (tsk->ptrace & PT_PTRACED) + if (task_ptrace(tsk) & PT_PTRACED) return rcu_dereference(tsk->parent); return NULL; } @@ -204,9 +179,6 @@ static inline void tracehook_report_exec { if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXEC))) utrace_report_exec(fmt, bprm, regs); - if (!ptrace_event(PT_TRACE_EXEC, PTRACE_EVENT_EXEC, 0) && - unlikely(task_ptrace(current) & PT_PTRACED)) - send_sig(SIGTRAP, current, 0); } /** @@ -223,7 +195,6 @@ static inline void tracehook_report_exit { if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXIT))) utrace_report_exit(exit_code); - ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code); if (unlikely(!list_empty(¤t->ptraced))) ptrace_utrace_exit(current); } @@ -330,8 +301,6 @@ static inline void tracehook_report_clon if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE)) && (clone_flags & CLONE_VFORK)) utrace_finish_vfork(current); - if (unlikely(trace)) - ptrace_event(0, trace, pid); } /** @@ -349,7 +318,6 @@ static inline void tracehook_report_clon static inline void tracehook_report_vfork_done(struct task_struct *child, pid_t pid) { - ptrace_event(PT_TRACE_VFORK_DONE, PTRACE_EVENT_VFORK_DONE, pid); } /** @@ -403,10 +371,6 @@ static inline void tracehook_signal_hand { if (task_utrace_flags(current)) utrace_signal_handler(current, stepping); -#ifndef CONFIG_UTRACE_PTRACE - if (stepping) - ptrace_notify(SIGTRAP); -#endif } /** --- PU/kernel/ptrace.c~01_REMOVE_OLD_CODE 2009-08-11 16:54:21.000000000 +0200 +++ PU/kernel/ptrace.c 2009-08-13 15:34:29.000000000 +0200 @@ -38,46 +38,6 @@ void __ptrace_link(struct task_struct *c child->parent = new_parent; } -#ifndef CONFIG_UTRACE_PTRACE -/* - * Turn a tracing stop into a normal stop now, since with no tracer there - * would be no way to wake it up with SIGCONT or SIGKILL. If there was a - * signal sent that would resume the child, but didn't because it was in - * TASK_TRACED, resume it now. - * Requires that irqs be disabled. - */ -static void ptrace_untrace(struct task_struct *child) -{ - spin_lock(&child->sighand->siglock); - if (task_is_traced(child)) { - /* - * If the group stop is completed or in progress, - * this thread was already counted as stopped. - */ - if (child->signal->flags & SIGNAL_STOP_STOPPED || - child->signal->group_stop_count) - __set_task_state(child, TASK_STOPPED); - else - signal_wake_up(child, 1); - } - spin_unlock(&child->sighand->siglock); -} - -static void ptrace_finish(struct task_struct *child) -{ - if (task_is_traced(child)) - ptrace_untrace(child); -} - -static void ptrace_detach_task(struct task_struct *child, int sig) -{ - /* Architecture-specific hardware disable .. */ - ptrace_disable(child); - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -} - -#else /* CONFIG_UTRACE_PTRACE */ - static const struct utrace_engine_ops ptrace_utrace_ops; /* forward decl */ static void ptrace_detach_task(struct task_struct *child, int sig) @@ -119,12 +79,6 @@ void ptrace_utrace_exit(struct task_stru read_unlock(&tasklist_lock); } -static void ptrace_finish(struct task_struct *child) -{ -} - -#endif /* !CONFIG_UTRACE_PTRACE */ - /* * unptrace a task: move it back to its original parent and * remove it from the ptrace list. @@ -140,72 +94,11 @@ void __ptrace_unlink(struct task_struct list_del_init(&child->ptrace_entry); arch_ptrace_untrace(child); - ptrace_finish(child); -} - -#ifndef CONFIG_UTRACE_PTRACE - -/* - * Check that we have indeed attached to the thing.. - */ -int ptrace_check_attach(struct task_struct *child, int kill) -{ - int ret = -ESRCH; - - /* - * We take the read lock around doing both checks to close a - * possible race where someone else was tracing our child and - * detached between these two checks. After this locked check, - * we are sure that this is our traced child and that can only - * be changed by us so it's not changing right after this. - */ - read_lock(&tasklist_lock); - if ((child->ptrace & PT_PTRACED) && child->parent == current) { - ret = 0; - /* - * child->sighand can't be NULL, release_task() - * does ptrace_unlink() before __exit_signal(). - */ - spin_lock_irq(&child->sighand->siglock); - if (task_is_stopped(child)) - child->state = TASK_TRACED; - else if (!task_is_traced(child) && !kill) - ret = -ESRCH; - spin_unlock_irq(&child->sighand->siglock); - } - read_unlock(&tasklist_lock); - - if (!ret && !kill) - ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH; - - /* All systems go.. */ - return ret; -} - -static struct utrace_engine *prepare_ptrace_attach( - struct task_struct *child, struct task_struct *parent) -{ - return NULL; -} - -static int finish_ptrace_attach(struct task_struct *task, - struct utrace_engine *engine, - int retval) -{ - return retval; } static int ptrace_update_utrace(struct task_struct *task, struct utrace_engine *engine) { - return 0; -} - -#else /* CONFIG_UTRACE_PTRACE */ - -static int ptrace_update_utrace(struct task_struct *task, - struct utrace_engine *engine) -{ unsigned long events; /* @@ -702,8 +595,6 @@ int ptrace_check_attach(struct task_stru return ret; } -#endif /* !CONFIG_UTRACE_PTRACE */ - int __ptrace_may_access(struct task_struct *task, unsigned int mode) { const struct cred *cred = current_cred(), *tcred; @@ -751,21 +642,6 @@ bool ptrace_may_access(struct task_struc return !err; } -#ifdef CONFIG_UTRACE_PTRACE -static inline bool exclude_ptrace(struct task_struct *task) -{ - return false; -} -#else -/* - * For experimental use of utrace, exclude ptrace on the same task. - */ -static inline bool exclude_ptrace(struct task_struct *task) -{ - return unlikely(!!task_utrace_flags(task)); -} -#endif - int ptrace_attach(struct task_struct *task) { int retval; @@ -794,8 +670,6 @@ int ptrace_attach(struct task_struct *ta task_lock(task); retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); - if (!retval && exclude_ptrace(task)) - retval = -EBUSY; task_unlock(task); if (retval) goto unlock_creds; @@ -1087,42 +961,6 @@ static int ptrace_setsiginfo(struct task #define is_sysemu_singlestep(request) 0 #endif -#ifndef CONFIG_UTRACE_PTRACE -static int ptrace_resume(struct task_struct *child, long request, long data) -{ - if (!valid_signal(data)) - return -EIO; - - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - -#ifdef TIF_SYSCALL_EMU - if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) - set_tsk_thread_flag(child, TIF_SYSCALL_EMU); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); -#endif - - if (is_singleblock(request)) { - if (unlikely(!arch_has_block_step())) - return -EIO; - user_enable_block_step(child); - } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { - if (unlikely(!arch_has_single_step())) - return -EIO; - user_enable_single_step(child); - } else { - user_disable_single_step(child); - } - - child->exit_code = data; - wake_up_process(child); - - return 0; -} -#else /* CONFIG_UTRACE_PTRACE */ static int ptrace_resume(struct task_struct *child, long request, long data) { struct utrace_engine *engine; @@ -1285,7 +1123,6 @@ static int ptrace_resume(struct task_str return ret; } -#endif /* !CONFIG_UTRACE_PTRACE */ int ptrace_request(struct task_struct *child, long request, long addr, long data) --- PU/kernel/utrace.c~01_REMOVE_OLD_CODE 2009-08-11 16:54:21.000000000 +0200 +++ PU/kernel/utrace.c 2009-08-13 15:10:55.000000000 +0200 @@ -107,21 +107,6 @@ static struct utrace_engine *matching_en return NULL; } -#ifdef CONFIG_UTRACE_PTRACE -static inline bool exclude_utrace(struct task_struct *task) -{ - return false; -} -#else -/* - * For experimental use, utrace attach is mutually exclusive with ptrace. - */ -static inline bool exclude_utrace(struct task_struct *task) -{ - return unlikely(!!task->ptrace); -} -#endif - /* * Called without locks, when we might be the first utrace engine to attach. * If this is a newborn thread and we are not the creator, we have to wait