[PATCH 136] (upstream) reorder the code in kernel/ptrace.c
No functional changes. Move the code which can be shared with utrace-ptrace up, before __ptrace_link(). --- kernel/ptrace.c | 556 1 file changed, 278 insertions(+), 278 deletions(-) --- UTRACE-PTRACE/kernel/ptrace.c~136_REORDER_FUNCS 2009-09-24 21:38:54.0 +0200 +++ UTRACE-PTRACE/kernel/ptrace.c 2009-11-21 21:41:41.0 +0100 @@ -23,6 +23,284 @@ #include linux/syscalls.h #include linux/uaccess.h +int __ptrace_may_access(struct task_struct *task, unsigned int mode) +{ + const struct cred *cred = current_cred(), *tcred; + + /* May we inspect the given task? +* This check is used both for attaching with ptrace +* and for allowing access to sensitive information in /proc. +* +* ptrace_attach denies several cases that /proc allows +* because setting up the necessary parent/child relationship +* or halting the specified task is impossible. +*/ + int dumpable = 0; + /* Don't let security modules deny introspection */ + if (task == current) + return 0; + rcu_read_lock(); + tcred = __task_cred(task); + if ((cred-uid != tcred-euid || +cred-uid != tcred-suid || +cred-uid != tcred-uid || +cred-gid != tcred-egid || +cred-gid != tcred-sgid || +cred-gid != tcred-gid) + !capable(CAP_SYS_PTRACE)) { + rcu_read_unlock(); + return -EPERM; + } + rcu_read_unlock(); + smp_rmb(); + if (task-mm) + dumpable = get_dumpable(task-mm); + if (!dumpable !capable(CAP_SYS_PTRACE)) + return -EPERM; + + return security_ptrace_access_check(task, mode); +} + +bool ptrace_may_access(struct task_struct *task, unsigned int mode) +{ + int err; + task_lock(task); + err = __ptrace_may_access(task, mode); + task_unlock(task); + return !err; +} + +/* + * Called with irqs disabled, returns true if childs should reap themselves. + */ +static int ignoring_children(struct sighand_struct *sigh) +{ + int ret; + spin_lock(sigh-siglock); + ret = (sigh-action[SIGCHLD-1].sa.sa_handler == SIG_IGN) || + (sigh-action[SIGCHLD-1].sa.sa_flags SA_NOCLDWAIT); + spin_unlock(sigh-siglock); + return ret; +} + +/* + * Called with tasklist_lock held for writing. + * Unlink a traced task, and clean it up if it was a traced zombie. + * Return true if it needs to be reaped with release_task(). + * (We can't call release_task() here because we already hold tasklist_lock.) + * + * If it's a zombie, our attachedness prevented normal parent notification + * or self-reaping. Do notification now if it would have happened earlier. + * If it should reap itself, return true. + * + * If it's our own child, there is no notification to do. But if our normal + * children self-reap, then this child was prevented by ptrace and we must + * reap it now, in that case we must also wake up sub-threads sleeping in + * do_wait(). + */ +static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) +{ + __ptrace_unlink(p); + + if (p-exit_state == EXIT_ZOMBIE) { + if (!task_detached(p) thread_group_empty(p)) { + if (!same_thread_group(p-real_parent, tracer)) + do_notify_parent(p, p-exit_signal); + else if (ignoring_children(tracer-sighand)) { + __wake_up_parent(p, tracer); + p-exit_signal = -1; + } + } + if (task_detached(p)) { + /* Mark it as in the process of being reaped. */ + p-exit_state = EXIT_DEAD; + return true; + } + } + + return false; +} + +int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) +{ + int copied = 0; + + while (len 0) { + char buf[128]; + int this_len, retval; + + this_len = (len sizeof(buf)) ? sizeof(buf) : len; + retval = access_process_vm(tsk, src, buf, this_len, 0); + if (!retval) { + if (copied) + break; + return -EIO; + } + if (copy_to_user(dst, buf, retval)) + return -EFAULT; + copied += retval; + src += retval; + dst += retval; + len -= retval; + } + return copied; +} + +int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len) +{ + int copied = 0; + + while (len 0) { + char buf[128]; + int this_len, retval; + +
[PATCH 139] kill CONFIG_UTRACE_PTRACE
If I understand correctly, we are not going to have CONFIG_UTRACE_PTRACE, CONFIG_UTRACE should use utrace-ptrace unconditionally. Remove CONFIG_UTRACE_PTRACE. I do not know where is the right place for CONFIG_UTRACE option and what the help text should say, I assume you can fix this patch or make the necessary changes on top. --- init/Kconfig| 20 +--- kernel/utrace.c |2 -- 2 files changed, 1 insertion(+), 21 deletions(-) --- UTRACE-PTRACE/init/Kconfig~139_KILL_CONFIG_UTRACE_PTRACE2009-11-13 18:00:06.0 +0100 +++ UTRACE-PTRACE/init/Kconfig 2009-11-22 17:05:10.0 +0100 @@ -1205,7 +1205,7 @@ config STOP_MACHINE help Need stop_machine() primitive. -menuconfig UTRACE +config UTRACE bool Infrastructure for tracing and debugging user processes depends on EXPERIMENTAL depends on HAVE_ARCH_TRACEHOOK @@ -1214,24 +1214,6 @@ menuconfig UTRACE kernel interface exported to kernel modules, to track events in user threads, extract and change user thread state. -config UTRACE_PTRACE - bool utrace-based ptrace (EXPERIMENTAL) - default y if UTRACE - depends on UTRACE - help - This changes the implementation of ptrace() to cooperate with the - utrace facility. Without this option, using any utrace facility - on a task that anything also uses ptrace() on (i.e. usual - debuggers, strace, etc) fails with -EBUSY; likewise, if utrace is - in use on a task, the ptrace() system call on that task will fail - with EBUSY. With this option, the ptrace() implementation is - changed to work via utrace facilities and the two cooperate well. - - It's recommended to enable this if you are experimenting with - new modules that use utrace. But, disabling it makes sure that - using traditional ptrace() on tasks not touched by utrace will - not use any experimental new code that might be unreliable. - source block/Kconfig config PREEMPT_NOTIFIERS --- UTRACE-PTRACE/kernel/utrace.c~139_KILL_CONFIG_UTRACE_PTRACE 2009-11-21 15:12:27.0 +0100 +++ UTRACE-PTRACE/kernel/utrace.c 2009-11-21 22:41:01.0 +0100 @@ -897,7 +897,6 @@ relock: spin_unlock_irq(task-sighand-siglock); spin_unlock(utrace-lock); -#ifdef CONFIG_UTRACE_PTRACE /* * If ptrace is among the reasons for this stop, do its * notification now. This could not just be done in @@ -906,7 +905,6 @@ relock: * synchronization with ptrace_do_wait() work right. */ ptrace_notify_stop(task); -#endif schedule();
[PATCH 3] ptrace: introduce user_single_step_siginfo() helper
(already in mm: ptrace-introduce-user_single_step_siginfo-helper.patch) Suggested by Roland. Currently there is no way to synthesize a single-stepping trap in the arch-independent manner. This patch adds the default helper which fills siginfo_t, arch/ can can override it. Architetures which implement user_enable_single_step() should add user_single_step_siginfo() also. Signed-off-by: Oleg Nesterov o...@redhat.com Acked-by: Roland McGrath rol...@redhat.com --- include/linux/ptrace.h | 12 1 file changed, 12 insertions(+) --- V1/include/linux/ptrace.h~3_DEFAULT_HELPER 2009-11-22 20:09:15.0 +0100 +++ V1/include/linux/ptrace.h 2009-11-22 20:10:37.0 +0100 @@ -273,6 +273,18 @@ static inline void user_enable_block_ste } #endif /* arch_has_block_step */ +#ifdef ARCH_HAS_USER_SINGLE_STEP_INFO +extern void user_single_step_siginfo(struct task_struct *tsk, + struct pt_regs *regs, siginfo_t *info); +#else +static inline void user_single_step_siginfo(struct task_struct *tsk, + struct pt_regs *regs, siginfo_t *info) +{ + memset(info, 0, sizeof(*info)); + info-si_signo = SIGTRAP; +} +#endif + #ifndef arch_ptrace_stop_needed /** * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called
[PATCH 7] ptrace: x86: change syscall_trace_leave() to rely on tracehook when stepping
(already in mm: ptrace-x86-change-syscall_trace_leave-to-rely-on-tracehook-when-stepping.patch) Suggested by Roland. Unlike powepc, x86 always calls tracehook_report_syscall_exit(step) with step = 0, and sends the trap by hand. This results in unnecessary SIGTRAP when PTRACE_SINGLESTEP follows the syscall-exit stop. Change syscall_trace_leave() to pass the correct step argument to tracehook and remove the send_sigtrap() logic. Signed-off-by: Oleg Nesterov o...@redhat.com Acked-by: Roland McGrath rol...@redhat.com --- arch/x86/kernel/ptrace.c | 21 +++-- 1 file changed, 7 insertions(+), 14 deletions(-) --- V1/arch/x86/kernel/ptrace.c~7_X86_CONVERT_SYSCALL_LEAVE 2009-11-22 20:26:48.0 +0100 +++ V1/arch/x86/kernel/ptrace.c 2009-11-22 20:28:37.0 +0100 @@ -1528,29 +1528,22 @@ asmregparm long syscall_trace_enter(stru asmregparm void syscall_trace_leave(struct pt_regs *regs) { + bool step; + if (unlikely(current-audit_context)) audit_syscall_exit(AUDITSC_RESULT(regs-ax), regs-ax); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs-ax); - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, 0); - /* * If TIF_SYSCALL_EMU is set, we only get here because of * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). * We already reported this syscall instruction in -* syscall_trace_enter(), so don't do any more now. -*/ - if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) - return; - - /* -* If we are single-stepping, synthesize a trap to follow the -* system call instruction. +* syscall_trace_enter(). */ - if (test_thread_flag(TIF_SINGLESTEP) - tracehook_consider_fatal_signal(current, SIGTRAP)) - send_sigtrap(current, regs, 0, TRAP_BRKPT); + step = unlikely(test_thread_flag(TIF_SINGLESTEP)) + !test_thread_flag(TIF_SYSCALL_EMU); + if (step || test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, step); }
[PATCH 8] tracehooks: kill some PT_PTRACED checks
No functional changes, preparation for utrace-ptrace. task_ptrace() != 0 if and only if PT_PTRACED bit is set, kill some PT_PTRACED checks in tracehook.h to ensure the result is the same with or without utrace which doesn't set PT_PTRACED. Signed-off-by: Oleg Nesterov o...@redhat.com --- include/linux/tracehook.h |6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) --- V1/include/linux/tracehook.h~8_TRACEHOOK_KILL_PTRACED_CHECKS 2009-11-22 20:24:14.0 +0100 +++ V1/include/linux/tracehook.h2009-11-22 20:43:09.0 +0100 @@ -156,7 +156,7 @@ static inline int tracehook_unsafe_exec( { int unsafe = 0; int ptrace = task_ptrace(task); - if (ptrace PT_PTRACED) { + if (ptrace) { if (ptrace PT_PTRACE_CAP) unsafe |= LSM_UNSAFE_PTRACE_CAP; else @@ -178,7 +178,7 @@ static inline int tracehook_unsafe_exec( */ static inline struct task_struct *tracehook_tracer_task(struct task_struct *tsk) { - if (task_ptrace(tsk) PT_PTRACED) + if (task_ptrace(tsk)) return rcu_dereference(tsk-parent); return NULL; } @@ -492,7 +492,7 @@ static inline int tracehook_get_signal(s */ static inline int tracehook_notify_jctl(int notify, int why) { - return notify ?: (current-ptrace PT_PTRACED) ? why : 0; + return notify ?: task_ptrace(current) ? why : 0; } /**
[PATCH 11] export __ptrace_detach() and do_notify_parent_cldstop()
Export __ptrace_detach() and do_notify_parent_cldstop() for ptrace-utrace. Signed-off-by: Oleg Nesterov o...@redhat.com --- include/linux/ptrace.h |1 + include/linux/sched.h |1 + kernel/ptrace.c|2 +- kernel/signal.c|2 +- 4 files changed, 4 insertions(+), 2 deletions(-) --- V1/include/linux/ptrace.h~11_EXPORT_2_HELPERS 2009-11-22 20:10:37.0 +0100 +++ V1/include/linux/ptrace.h 2009-11-22 21:45:53.0 +0100 @@ -85,6 +85,7 @@ extern int ptrace_traceme(void); extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); extern int ptrace_attach(struct task_struct *tsk); +extern bool __ptrace_detach(struct task_struct *tracer, struct task_struct *tracee); 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); --- V1/include/linux/sched.h~11_EXPORT_2_HELPERS2009-09-24 21:38:54.0 +0200 +++ V1/include/linux/sched.h2009-11-22 21:43:20.0 +0100 @@ -2060,6 +2060,7 @@ extern int kill_pgrp(struct pid *pid, in extern int kill_pid(struct pid *pid, int sig, int priv); extern int kill_proc_info(int, struct siginfo *, pid_t); extern int do_notify_parent(struct task_struct *, int); +extern void do_notify_parent_cldstop(struct task_struct *, int); extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent); extern void force_sig(int, struct task_struct *); extern void force_sig_specific(int, struct task_struct *); --- V1/kernel/ptrace.c~11_EXPORT_2_HELPERS 2009-09-24 21:38:54.0 +0200 +++ V1/kernel/ptrace.c 2009-11-22 21:50:11.0 +0100 @@ -271,7 +271,7 @@ static int ignoring_children(struct sigh * reap it now, in that case we must also wake up sub-threads sleeping in * do_wait(). */ -static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) +bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) { __ptrace_unlink(p); --- V1/kernel/signal.c~11_EXPORT_2_HELPERS 2009-11-22 21:30:52.0 +0100 +++ V1/kernel/signal.c 2009-11-22 21:51:17.0 +0100 @@ -1461,7 +1461,7 @@ int do_notify_parent(struct task_struct return ret; } -static void do_notify_parent_cldstop(struct task_struct *tsk, int why) +void do_notify_parent_cldstop(struct task_struct *tsk, int why) { struct siginfo info; unsigned long flags;
Re: [PATCH 3] ptrace: introduce user_single_step_siginfo() helper
+#ifdef ARCH_HAS_USER_SINGLE_STEP_INFO +extern void user_single_step_siginfo(struct task_struct *tsk, + struct pt_regs *regs, siginfo_t *info); +#else +static inline void user_single_step_siginfo(struct task_struct *tsk, + struct pt_regs *regs, siginfo_t *info) +{ + memset(info, 0, sizeof(*info)); + info-si_signo = SIGTRAP; Is it possible to add si_code and si_addr info info-si_code = TRAP_TRACE; info-si_addr = instruction_pointer(regs); +} +#endif + Thanks and Regards -Srikar
Re: [PATCH 3] ptrace: introduce user_single_step_siginfo() helper
Is it possible to add si_code and si_addr info info-si_code = TRAP_TRACE; info-si_addr = instruction_pointer(regs); This is exactly what arch-specific versions should do here. The choice of TRAP_TRACE is an arch detail, not a common default. Thanks, Roland