[PATCH 3/7] ptrace_init_task: cleanup the usage of ptrace_link()

2009-10-25 Thread Oleg Nesterov
No functional changes, preparation for utrace-ptrace.

ptrace_init_task() looks confusing, as if we always auto-attach when
bool ptrace argument is true, while in fact we attach only if current
is traced.

Make the code more explicit and kill now unused ptrace_link().

Signed-off-by: Oleg Nesterov o...@redhat.com
---

 include/linux/ptrace.h |   11 +++
 1 file changed, 3 insertions(+), 8 deletions(-)

--- V1/include/linux/ptrace.h~3_PTRACE_INIT_TASK2009-06-19 
01:12:47.0 +0200
+++ V1/include/linux/ptrace.h   2009-10-26 00:33:58.0 +0100
@@ -105,12 +105,7 @@ static inline int ptrace_reparented(stru
 {
return child-real_parent != child-parent;
 }
-static inline void ptrace_link(struct task_struct *child,
-  struct task_struct *new_parent)
-{
-   if (unlikely(child-ptrace))
-   __ptrace_link(child, new_parent);
-}
+
 static inline void ptrace_unlink(struct task_struct *child)
 {
if (unlikely(child-ptrace))
@@ -169,9 +164,9 @@ static inline void ptrace_init_task(stru
INIT_LIST_HEAD(child-ptraced);
child-parent = child-real_parent;
child-ptrace = 0;
-   if (unlikely(ptrace)) {
+   if (unlikely(ptrace)  (current-ptrace  PT_PTRACED)) {
child-ptrace = current-ptrace;
-   ptrace_link(child, current-parent);
+   __ptrace_link(child, current-parent);
}
 }
 



[PATCH 4/7] ptrace_signal: check PT_PTRACED

2009-10-25 Thread Oleg Nesterov
No functional changes, preparation for utrace-ptrace.

Change ptrace_signal() to check PT_PTRACED instead of task_ptrace() != 0.
Currently this is the same, PT_PTRACED must be always set if the task is
ptraced.

This change is needed to make sure ptrace_sgnal() does nothing if ptrace
is implemented on top of utrace.

Signed-off-by: Oleg Nesterov o...@redhat.com
---

 kernel/signal.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- V1/kernel/signal.c~4_PTRACE_SIGNAL_CK_PTRACED   2009-09-24 
21:38:54.0 +0200
+++ V1/kernel/signal.c  2009-10-26 00:43:05.0 +0100
@@ -1731,7 +1731,7 @@ static int do_signal_stop(int signr)
 static int ptrace_signal(int signr, siginfo_t *info,
 struct pt_regs *regs, void *cookie)
 {
-   if (!task_ptrace(current))
+   if (!(task_ptrace(current)  PT_PTRACED))
return signr;
 
ptrace_signal_deliver(regs, cookie);



[PATCH 5/7] signals: check -group_stop_count after tracehook_get_signal()

2009-10-25 Thread Oleg Nesterov
No functional changes, preparation for utrace-ptrace.

Move the call to do_signal_stop() down, after tracehook call.
This makes -group_stop_count condition visible to tracers before
do_signal_stop() will participate in this group-stop.

Currently the patch has no effect, tracehook_get_signal() always
returns 0.

Signed-off-by: Oleg Nesterov o...@redhat.com
---

 kernel/signal.c |9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

--- V1/kernel/signal.c~5_DO_SIGNAL_STOP_AFTER_TRACEHOOK 2009-10-26 
00:43:05.0 +0100
+++ V1/kernel/signal.c  2009-10-26 01:01:47.0 +0100
@@ -1807,11 +1807,6 @@ relock:
 
for (;;) {
struct k_sigaction *ka;
-
-   if (unlikely(signal-group_stop_count  0) 
-   do_signal_stop(0))
-   goto relock;
-
/*
 * Tracing can induce an artifical signal and choose sigaction.
 * The return value in @signr determines the default action,
@@ -1823,6 +1818,10 @@ relock:
if (unlikely(signr != 0))
ka = return_ka;
else {
+   if (unlikely(signal-group_stop_count  0) 
+   do_signal_stop(0))
+   goto relock;
+
signr = dequeue_signal(current, current-blocked,
   info);
 



[PATCH 6/7] introduce kernel/ptrace.h

2009-10-25 Thread Oleg Nesterov
No functional changes, preparation for utrace-ptrace.

Introduce kernel/ptrace.h and move the code which can be shared
with the new implementation into this new header.

Signed-off-by: Oleg Nesterov o...@redhat.com
---

 kernel/ptrace-common.h |  278 
 kernel/ptrace.c|  280 -
 2 files changed, 279 insertions(+), 279 deletions(-)

--- /dev/null   2009-10-25 19:46:00.608018007 +0100
+++ V1/kernel/ptrace-common.h   2009-10-26 02:20:44.0 +0100
@@ -0,0 +1,278 @@
+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) {
+ 

Re: [PATCH 0/7] utrace-ptrace V1

2009-10-25 Thread Oleg Nesterov
On 10/26, Oleg Nesterov wrote:

 For early review.

 Patches 1-5 can be sent upstream right now. The last 2 patches
 add the new implementation.

 utrace.patch can come before or after, I think after is better.

Forgot to mention, this series is against Linus's tree.

Oleg.