[PATCH 136] (upstream) reorder the code in kernel/ptrace.c

2009-11-22 Thread Oleg Nesterov
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

2009-11-22 Thread Oleg Nesterov
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

2009-11-22 Thread Oleg Nesterov
(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

2009-11-22 Thread Oleg Nesterov
(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

2009-11-22 Thread Oleg Nesterov
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()

2009-11-22 Thread Oleg Nesterov
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

2009-11-22 Thread Srikar Dronamraju
 
 +#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

2009-11-22 Thread Roland McGrath
 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