rpms/kernel/devel linux-2.6-utrace.patch,1.45,1.46

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Sun Dec 24 00:03:16 UTC 2006


Author: roland

Update of /cvs/dist/rpms/kernel/devel
In directory cvs.devel.redhat.com:/tmp/cvs-serv9814

Modified Files:
	linux-2.6-utrace.patch 
Log Message:
utrace rebase, update with race fixes

linux-2.6-utrace.patch:
 Documentation/utrace.txt            |  579 +++++++++++
 arch/alpha/kernel/asm-offsets.c     |    2 
 arch/alpha/kernel/entry.S           |    4 
 arch/arm/kernel/ptrace.c            |   36 
 arch/arm26/kernel/ptrace.c          |   32 
 arch/frv/kernel/ptrace.c            |   15 
 arch/i386/kernel/entry.S            |    7 
 arch/i386/kernel/i387.c             |  143 +-
 arch/i386/kernel/process.c          |    3 
 arch/i386/kernel/ptrace.c           |  863 +++++++++-------
 arch/i386/kernel/signal.c           |   37 
 arch/i386/kernel/vm86.c             |    7 
 arch/ia64/ia32/ia32_entry.S         |    2 
 arch/ia64/ia32/sys_ia32.c           |  537 ++++++++++
 arch/ia64/kernel/asm-offsets.c      |    2 
 arch/ia64/kernel/fsys.S             |   16 
 arch/ia64/kernel/mca.c              |    2 
 arch/ia64/kernel/ptrace.c           | 1680 ++++++++++++++++----------------
 arch/ia64/kernel/signal.c           |    4 
 arch/mips/kernel/ptrace.c           |   21 
 arch/mips/kernel/sysirix.c          |    2 
 arch/powerpc/kernel/Makefile        |    4 
 arch/powerpc/kernel/asm-offsets.c   |    2 
 arch/powerpc/kernel/process.c       |    5 
 arch/powerpc/kernel/ptrace-common.h |  161 ---
 arch/powerpc/kernel/ptrace.c        |  959 +++++++++++-------
 arch/powerpc/kernel/ptrace32.c      |  436 --------
 arch/powerpc/kernel/signal_32.c     |   55 +
 arch/powerpc/kernel/signal_64.c     |    3 
 arch/powerpc/kernel/sys_ppc32.c     |    5 
 arch/powerpc/lib/sstep.c            |    3 
 arch/ppc/kernel/asm-offsets.c       |    2 
 arch/s390/kernel/Makefile           |    2 
 arch/s390/kernel/compat_linux.c     |    3 
 arch/s390/kernel/compat_signal.c    |    5 
 arch/s390/kernel/process.c          |    3 
 arch/s390/kernel/ptrace.c           | 1073 +++++++++-----------
 arch/s390/kernel/signal.c           |    3 
 arch/s390/kernel/traps.c            |    6 
 arch/sparc64/kernel/Makefile        |    2 
 arch/sparc64/kernel/binfmt_aout32.c |    2 
 arch/sparc64/kernel/entry.S         |    6 
 arch/sparc64/kernel/process.c       |    3 
 arch/sparc64/kernel/ptrace.c        | 1224 ++++++++++++-----------
 arch/sparc64/kernel/signal.c        |    2 
 arch/sparc64/kernel/signal32.c      |    2 
 arch/sparc64/kernel/sys_sparc32.c   |    3 
 arch/sparc64/kernel/systbls.S       |    4 
 arch/x86_64/ia32/fpu32.c            |   92 +
 arch/x86_64/ia32/ia32_aout.c        |    6 
 arch/x86_64/ia32/ia32_signal.c      |    7 
 arch/x86_64/ia32/ia32entry.S        |    2 
 arch/x86_64/ia32/ptrace32.c         |  723 +++++++++----
 arch/x86_64/ia32/sys_ia32.c         |    5 
 arch/x86_64/kernel/process.c        |    5 
 arch/x86_64/kernel/ptrace.c         |  657 +++++++-----
 arch/x86_64/kernel/signal.c         |   28 
 arch/x86_64/kernel/traps.c          |    8 
 arch/x86_64/mm/fault.c              |    4 
 drivers/connector/cn_proc.c         |    4 
 fs/binfmt_aout.c                    |    6 
 fs/binfmt_elf.c                     |    6 
 fs/binfmt_elf_fdpic.c               |    7 
 fs/binfmt_flat.c                    |    3 
 fs/binfmt_som.c                     |    2 
 fs/exec.c                           |   11 
 fs/proc/array.c                     |   12 
 fs/proc/base.c                      |   17 
 include/asm-i386/i387.h             |   13 
 include/asm-i386/signal.h           |    4 
 include/asm-i386/thread_info.h      |    7 
 include/asm-i386/tracehook.h        |   49 
 include/asm-ia64/elf.h              |   24 
 include/asm-ia64/tracehook.h        |   83 +
 include/asm-powerpc/tracehook.h     |   80 +
 include/asm-s390/tracehook.h        |   53 +
 include/asm-sparc64/tracehook.h     |   44 
 include/asm-x86_64/fpu32.h          |    3 
 include/asm-x86_64/thread_info.h    |    3 
 include/asm-x86_64/tracehook.h      |   54 +
 include/linux/init_task.h           |    3 
 include/linux/ptrace.h              |  224 +++-
 include/linux/sched.h               |   25 
 include/linux/tracehook.h           |  707 +++++++++++++
 include/linux/utrace.h              |  504 +++++++++
 init/Kconfig                        |   29 
 kernel/Makefile                     |    1 
 kernel/exit.c                       |  244 +---
 kernel/fork.c                       |   62 -
 kernel/ptrace.c                     | 1767 ++++++++++++++++++++++++++++------
 kernel/signal.c                     |  211 ----
 kernel/sys.c                        |    2 
 kernel/timer.c                      |    6 
 kernel/tsacct.c                     |    2 
 kernel/utrace.c                     | 1861 ++++++++++++++++++++++++++++++++++++
 security/selinux/hooks.c            |   54 -
 security/selinux/include/objsec.h   |    1 
 97 files changed, 10644 insertions(+), 5053 deletions(-)

Index: linux-2.6-utrace.patch
===================================================================
RCS file: /cvs/dist/rpms/kernel/devel/linux-2.6-utrace.patch,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -r1.45 -r1.46
--- linux-2.6-utrace.patch	14 Dec 2006 14:17:26 -0000	1.45
+++ linux-2.6-utrace.patch	24 Dec 2006 00:03:12 -0000	1.46
@@ -34,7 +34,7 @@
  arch/s390/kernel/compat_linux.c     |    3 
  arch/s390/kernel/compat_signal.c    |    5 
  arch/s390/kernel/process.c          |    3 
- arch/s390/kernel/ptrace.c           | 1073 ++++++++++----------
+ arch/s390/kernel/ptrace.c           | 1073 +++++++++-----------
  arch/s390/kernel/signal.c           |    3 
  arch/s390/kernel/traps.c            |    6 
  arch/sparc64/Makefile               |    0 
@@ -77,7 +77,7 @@
  include/asm-s390/tracehook.h        |   53 +
  include/asm-sparc64/tracehook.h     |   44 +
  include/asm-x86_64/fpu32.h          |    3 
- include/asm-x86_64/thread_info.h    |    2 
+ include/asm-x86_64/thread_info.h    |    3 
  include/asm-x86_64/tracehook.h      |   54 +
  include/linux/init_task.h           |    3 
  include/linux/ptrace.h              |  224 +++-
@@ -88,15 +88,15 @@
  kernel/Makefile                     |    1 
  kernel/exit.c                       |  244 +----
  kernel/fork.c                       |   62 -
- kernel/ptrace.c                     | 1633 +++++++++++++++++++++++++------
+ kernel/ptrace.c                     | 1767 +++++++++++++++++++++++++++------
  kernel/signal.c                     |  211 +---
  kernel/sys.c                        |    2 
  kernel/timer.c                      |    6 
  kernel/tsacct.c                     |    2 
- kernel/utrace.c                     | 1860 +++++++++++++++++++++++++++++++++++
+ kernel/utrace.c                     | 1861 +++++++++++++++++++++++++++++++++++
  security/selinux/hooks.c            |   54 +
  security/selinux/include/objsec.h   |    1 
- 98 files changed, 10509 insertions(+), 5052 deletions(-)
+ 98 files changed, 10644 insertions(+), 5053 deletions(-)
  create mode 100644 Documentation/utrace.txt
  delete arch/powerpc/kernel/ptrace-common.h
  delete arch/powerpc/kernel/ptrace32.c
@@ -350,8 +350,8 @@
  	} while (0)
  
  #endif /* __KERNEL__ */
---- linux-2.6.19.noarch/include/asm-i386/thread_info.h~	2006-12-14 09:11:23.000000000 -0500
-+++ linux-2.6.19.noarch/include/asm-i386/thread_info.h	2006-12-14 09:12:44.000000000 -0500
+--- linux-2.6/include/asm-i386/thread_info.h.utrace-ptrace-compat
++++ linux-2.6/include/asm-i386/thread_info.h
 @@ -127,7 +127,6 @@ static inline struct thread_info *curren
  #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
  #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
@@ -364,7 +364,7 @@
  #define TIF_DEBUG		17	/* uses debug registers */
  #define TIF_IO_BITMAP		18	/* uses I/O bitmap */
  #define TIF_FREEZE		19	/* is freezing for suspend */
-+#define TIF_FORCED_TF		20	/* syscall emulation active */
++#define TIF_FORCED_TF		20	/* true if TF in eflags artificially */
  
  #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
  #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -379,13 +379,13 @@
  #define _TIF_DEBUG		(1<<TIF_DEBUG)
  #define _TIF_IO_BITMAP		(1<<TIF_IO_BITMAP)
  #define _TIF_FREEZE		(1<<TIF_FREEZE)
-+#define _TIF_FORCED_EMU	(1<<TIF_FORCED_TF)
++#define _TIF_FORCED_TF		(1<<TIF_FORCED_TF)
  
  /* work to do on interrupt/exception return */
  #define _TIF_WORK_MASK \
 -  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
 -		  _TIF_SECCOMP | _TIF_SYSCALL_EMU))
-+	(0x0000FFFF & ~(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP))
++  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP))
  /* work to do on any return to u-space */
  #define _TIF_ALLWORK_MASK	(0x0000FFFF & ~_TIF_SECCOMP)
  
@@ -507,24 +507,25 @@
 +int set_fpregs32(struct task_struct *, const struct user_i387_ia32_struct *);
 +
  #endif
---- linux-2.6.19.noarch/include/asm-x86_64/thread_info.h~	2006-12-14 09:13:22.000000000 -0500
-+++ linux-2.6.19.noarch/include/asm-x86_64/thread_info.h	2006-12-14 09:13:53.000000000 -0500
-@@ -123,6 +123,7 @@ static inline struct thread_info *stack_
- #define TIF_DEBUG		21	/* uses debug registers */
- #define TIF_IO_BITMAP		22	/* uses I/O bitmap */
- #define TIF_FREEZE		23	/* is freezing for suspend */
-+#define TIF_FORCED_TF		24	/* true if TF in eflags artificially */
- 
- #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
- #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-@@ -139,6 +140,7 @@ static inline struct thread_info *stack_
- #define _TIF_DEBUG		(1<<TIF_DEBUG)
- #define _TIF_IO_BITMAP		(1<<TIF_IO_BITMAP)
- #define _TIF_FREEZE		(1<<TIF_FREEZE)
+--- linux-2.6/include/asm-x86_64/thread_info.h.utrace-ptrace-compat
++++ linux-2.6/include/asm-x86_64/thread_info.h
+@@ -115,7 +115,7 @@ static inline struct thread_info *stack_
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_SECCOMP		8	/* secure computing */
+ #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal */
+-/* 16 free */
++#define TIF_FORCED_TF		16	/* true if TF in eflags artificially */
+ #define TIF_IA32		17	/* 32bit process */ 
+ #define TIF_FORK		18	/* ret_from_fork */
+ #define TIF_ABI_PENDING		19
+@@ -133,6 +133,7 @@ static inline struct thread_info *stack_
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+ #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 +#define _TIF_FORCED_TF		(1<<TIF_FORCED_TF)
- 
- /* work to do on interrupt/exception return */
- #define _TIF_WORK_MASK \
+ #define _TIF_IA32		(1<<TIF_IA32)
+ #define _TIF_FORK		(1<<TIF_FORK)
+ #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
 --- linux-2.6/include/asm-x86_64/tracehook.h.utrace-ptrace-compat
 +++ linux-2.6/include/asm-x86_64/tracehook.h
 @@ -0,0 +1,54 @@
@@ -702,7 +703,7 @@
  	/*
  	 * cache last used pipe for splice
  	 */
-@@ -1331,6 +1329,7 @@ extern int kill_pid(struct pid *pid, int
+@@ -1330,6 +1328,7 @@ extern int kill_pid(struct pid *pid, int
  extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
  extern int kill_pg_info(int, struct siginfo *, pid_t);
  extern void do_notify_parent(struct task_struct *, int);
@@ -1459,7 +1460,7 @@
  #ifndef force_successful_syscall_return
 --- linux-2.6/include/linux/init_task.h.utrace-ptrace-compat
 +++ linux-2.6/include/linux/init_task.h
-@@ -111,9 +111,6 @@ extern struct group_info init_groups;
+@@ -110,9 +110,6 @@ extern struct group_info init_groups;
  	.ioprio		= 0,						\
  	.time_slice	= HZ,						\
  	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
@@ -3280,7 +3281,7 @@
  		read_lock(&tasklist_lock);
  		do_notify_parent_cldstop(current, CLD_STOPPED);
  		read_unlock(&tasklist_lock);
-@@ -1824,44 +1718,24 @@ relock:
+@@ -1826,44 +1720,24 @@ relock:
  		    handle_group_stop())
  			goto relock;
  
@@ -3341,7 +3342,7 @@
  		if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
  			continue;
  		if (ka->sa.sa_handler != SIG_DFL) {
-@@ -1910,7 +1784,7 @@ relock:
+@@ -1912,7 +1786,7 @@ relock:
  				spin_lock_irq(&current->sighand->siglock);
  			}
  
@@ -3350,7 +3351,7 @@
  				/* It released the siglock.  */
  				goto relock;
  			}
-@@ -1937,13 +1811,13 @@ relock:
+@@ -1939,13 +1813,13 @@ relock:
  			 * first and our do_group_exit call below will use
  			 * that value and ignore the one we pass it.
  			 */
@@ -3366,7 +3367,7 @@
  		/* NOTREACHED */
  	}
  	spin_unlock_irq(&current->sighand->siglock);
-@@ -1956,7 +1830,6 @@ EXPORT_SYMBOL(flush_signals);
+@@ -1958,7 +1832,6 @@ EXPORT_SYMBOL(flush_signals);
  EXPORT_SYMBOL(force_sig);
  EXPORT_SYMBOL(kill_pg);
  EXPORT_SYMBOL(kill_proc);
@@ -3387,7 +3388,7 @@
  	stats->ac_stime	 = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC;
 --- linux-2.6/kernel/utrace.c.utrace-ptrace-compat
 +++ linux-2.6/kernel/utrace.c
-@@ -0,0 +1,1860 @@
+@@ -0,0 +1,1861 @@
 +#include <linux/utrace.h>
 +#include <linux/tracehook.h>
 +#include <linux/err.h>
@@ -4883,6 +4884,7 @@
 +			sigdelset(&sigkill_only, SIGKILL);
 +			killed = dequeue_signal(tsk, &sigkill_only, info);
 +			BUG_ON(killed != SIGKILL);
++			*return_ka = tsk->sighand->action[killed - 1];
 +			return killed;
 +		}
 +	}
@@ -5732,7 +5734,7 @@
  			goto out;
 --- linux-2.6/kernel/timer.c.utrace-ptrace-compat
 +++ linux-2.6/kernel/timer.c
-@@ -1242,9 +1242,9 @@ asmlinkage long sys_getpid(void)
+@@ -1246,9 +1246,9 @@ asmlinkage long sys_getpid(void)
  }
  
  /*
@@ -5744,7 +5746,7 @@
   * release_task()->call_rcu(delayed_put_task_struct).
   */
  asmlinkage long sys_getppid(void)
-@@ -1252,7 +1252,7 @@ asmlinkage long sys_getppid(void)
+@@ -1256,7 +1256,7 @@ asmlinkage long sys_getppid(void)
  	int pid;
  
  	rcu_read_lock();
@@ -5864,7 +5866,7 @@
  
  static int may_attach(struct task_struct *task)
  {
-@@ -157,334 +71,1433 @@ int ptrace_may_attach(struct task_struct
+@@ -157,334 +71,1567 @@ int ptrace_may_attach(struct task_struct
  	return !err;
  }
  
@@ -5917,8 +5919,6 @@
 +		struct rcu_head dead;
 +		struct {
 +			u8 options; /* PTRACE_SETOPTIONS bits.  */
-+			unsigned int stopped:1;	/* Stopped for report.  */
-+			unsigned int reported:1; /* wait already reported.  */
 +			unsigned int syscall:1;	/* Reporting for syscall.  */
 +#ifdef PTRACE_SYSEMU
 +			unsigned int sysemu:1; /* PTRACE_SYSEMU in progress. */
@@ -5937,15 +5937,6 @@
 +
 +static const struct utrace_engine_ops ptrace_utrace_ops; /* Initialized below. */
 +
-+
-+static void
-+ptrace_state_link(struct ptrace_state *state)
-+{
-+	task_lock(state->parent);
-+	list_add_rcu(&state->entry, &state->parent->ptracees);
-+	task_unlock(state->parent);
-+}
-+
 +static void
 +ptrace_state_unlink(struct ptrace_state *state)
 +{
@@ -5954,25 +5945,37 @@
 +	task_unlock(state->parent);
 +}
 +
-+static int
++static struct ptrace_state *
 +ptrace_setup(struct task_struct *target, struct utrace_attached_engine *engine,
-+	     struct task_struct *parent, u8 options, int cap_sys_ptrace)
++	     struct task_struct *parent, u8 options, int cap_sys_ptrace,
++	     struct ptrace_state *state)
 +{
-+	struct ptrace_state *state = kzalloc(sizeof *state, GFP_USER);
-+	if (unlikely(state == NULL))
-+		return -ENOMEM;
++	if (state == NULL) {
++		state = kzalloc(sizeof *state, GFP_USER);
++		if (unlikely(state == NULL))
++			return ERR_PTR(-ENOMEM);
++	}
 +
 +	state->engine = engine;
 +	state->task = target;
 +	state->parent = parent;
 +	state->u.live.options = options;
 +	state->u.live.cap_sys_ptrace = cap_sys_ptrace;
-+	ptrace_state_link(state);
 +
++	task_lock(parent);
++	if (unlikely(parent->flags & PF_EXITING)) {
++		task_unlock(parent);
++		kfree(state);
++		return ERR_PTR(-EALREADY);
+ 	}
++	list_add_rcu(&state->entry, &state->parent->ptracees);
++	task_unlock(state->parent);
+ 
+-	if (!task->mm)
 +	BUG_ON(engine->data != 0);
 +	rcu_assign_pointer(engine->data, (unsigned long) state);
 +
-+	return 0;
++	return state;
 +}
 +
 +static void
@@ -6021,16 +6024,22 @@
 +
 +	/*
 +	 * ptrace always inhibits normal parent reaping.
-+	 * But for a corner case we sometimes see the REAP event instead.
++	 * But for a corner case we sometimes see the REAP event anyway.
 +	 */
 +	flags |= UTRACE_ACTION_NOREAP | UTRACE_EVENT(REAP);
 +
-+	state->u.live.stopped = (flags & UTRACE_ACTION_QUIESCE) != 0;
-+	if (!state->u.live.stopped) {
++	if (!(flags & UTRACE_ACTION_QUIESCE)) {
++		/*
++		 * We're letting the thread resume from ptrace stop.
++		 * If SIGKILL is waking it up, it can be racing with us here
++		 * to set its own exit_code in do_exit.  Though we clobber
++		 * it here, we check for the case in ptrace_report_death.
++		 */
++		if (!unlikely(target->flags & PF_SIGNALED))
++			target->exit_code = 0;
++
 +		if (!state->u.live.have_eventmsg)
 +			state->u.live.u.siginfo = NULL;
-+		if (!(target->flags & PF_EXITING))
-+			target->exit_code = 0;
 +
 +		if (target->state == TASK_STOPPED) {
 +			spin_lock_irq(&target->sighand->siglock);
@@ -6039,12 +6048,15 @@
 +			spin_unlock_irq(&target->sighand->siglock);
 +		}
 +	}
++
 +	return utrace_set_flags(target, engine, flags);
 +}
 +
 +static int ptrace_traceme(void)
 +{
 +	struct utrace_attached_engine *engine;
++	struct ptrace_state *state;
++	struct task_struct *parent;
 +	int retval;
 +
 +	engine = utrace_attach(current, (UTRACE_ATTACH_CREATE
@@ -6058,27 +6070,64 @@
 +			retval = -EPERM;
 +	}
 +	else {
++		/*
++		 * We need to preallocate so that we can hold
++		 * rcu_read_lock from extracting ->parent through
++		 * ptrace_setup using it.
++		 */
++		state = kzalloc(sizeof *state, GFP_USER);
++		if (unlikely(state == NULL)) {
++			(void) utrace_detach(current, engine);
++			printk(KERN_ERR
++			       "ptrace out of memory, lost child %d of %d",
++			       current->pid, current->parent->pid);
++			return -ENOMEM;
++		}
++
++		rcu_read_lock();
++		parent = rcu_dereference(current->parent);
++
 +		task_lock(current);
-+		retval = security_ptrace(current->parent, current);
++		retval = security_ptrace(parent, current);
 +		task_unlock(current);
-+		if (!retval)
-+			retval = ptrace_setup(current, engine,
-+					      current->parent, 0, 0);
++
++		if (retval) {
++			kfree(state);
++			(void) utrace_detach(current, engine);
++		}
++		else {
++			state = ptrace_setup(current, engine, parent, 0, 0,
++					     state);
++			if (IS_ERR(state))
++				retval = PTR_ERR(state);
++		}
++		rcu_read_unlock();
++
 +		if (!retval) {
++			/*
++			 * This can't fail because we can't die while we
++			 * are here doing this.
++			 */
 +			retval = ptrace_update(current, engine, 0);
 +			BUG_ON(retval);
 +		}
-+		if (retval)
-+			utrace_detach(current, engine);
- 	}
- 
--	if (!task->mm)
++		else if (unlikely(retval == -EALREADY))
++			/*
++			 * We raced with our parent's exit, which would
++			 * have detached us just after our attach if
++			 * we'd won the race.  Pretend we got attached
++			 * and then detached immediately, no error.
++			 */
++			retval = 0;
++	}
++
 +	return retval;
 +}
 +
 +static int ptrace_attach(struct task_struct *task)
 +{
 +	struct utrace_attached_engine *engine;
++	struct ptrace_state *state;
 +	int retval;
 +
 +	retval = -EPERM;
@@ -6112,19 +6161,27 @@
 +	}
  
 -	force_sig_specific(SIGSTOP, task);
-+	if (ptrace_may_attach(task))
-+		retval = ptrace_setup(task, engine, current, 0,
-+				      capable(CAP_SYS_PTRACE));
-+	if (!retval) {
-+		retval = ptrace_update(task, engine, 0);
-+		if (retval) {
-+			if (retval == -EALREADY)
-+				retval = -ESRCH;
-+			BUG_ON(retval != -ESRCH);
++	if (ptrace_may_attach(task)) {
++		state = ptrace_setup(task, engine, current, 0,
++				     capable(CAP_SYS_PTRACE), NULL);
++		if (IS_ERR(state))
++			retval = PTR_ERR(state);
++		else {
++			retval = ptrace_update(task, engine, 0);
++			if (retval) {
++				/*
++				 * It died before we enabled any callbacks.
++				 */
++				if (retval == -EALREADY)
++					retval = -ESRCH;
++				BUG_ON(retval != -ESRCH);
++				ptrace_state_unlink(state);
++				ptrace_done(state);
++			}
 +		}
 +	}
 +	if (retval)
-+		utrace_detach(task, engine);
++		(void) utrace_detach(task, engine);
 +	else {
 +		int stopped;
 +
@@ -6169,8 +6226,26 @@
 +	struct ptrace_state *state = (struct ptrace_state *) engine->data;
 +	int error = utrace_detach(task, engine);
 +	if (!error) {
++		/*
++		 * We can only get here from the ptracer itself or via
++		 * detach_zombie from another thread in its group.
++		 */
++		BUG_ON(state->parent->tgid != current->tgid);
 +		ptrace_state_unlink(state);
 +		ptrace_done(state);
++
++		/*
++		 * Wake up any other threads that might be blocked in
++		 * wait.  Though traditional ptrace does not guarantee
++		 * this wakeup on PTRACE_DETACH, it does prevent
++		 * erroneous blocking in wait when another racing
++		 * thread's wait call reap-detaches the last child.
++		 * Without this wakeup, another thread might stay
++		 * blocked when it should return -ECHILD.
++		 */
++		spin_lock_irq(&current->sighand->siglock);
++		wake_up_interruptible(&current->signal->wait_chldexit);
++		spin_unlock_irq(&current->sighand->siglock);
 +	}
 +	return error;
  }
@@ -6184,30 +6259,51 @@
 +ptrace_exit(struct task_struct *tsk)
  {
 -	if (!valid_signal(data))
-+	rcu_read_lock();
-+	if (unlikely(!list_empty(&tsk->ptracees))) {
-+		struct ptrace_state *state, *next;
++	struct list_head *pos, *n;
 +
-+		/*
-+		 * First detach the utrace layer from all the tasks.
-+		 * We don't want to hold any locks while calling utrace_detach.
-+		 */
-+		list_for_each_entry_rcu(state, &tsk->ptracees, entry) {
-+			rcu_assign_pointer(state->engine->data, 0UL);
-+			(void) utrace_detach(state->task, state->engine);
-+		}
++	/*
++	 * Taking the task_lock after PF_EXITING is set ensures that a
++	 * child in ptrace_traceme will not put itself on our list when
++	 * we might already be tearing it down.
++	 */
++	task_lock(tsk);
++	if (likely(list_empty(&tsk->ptracees))) {
++		task_unlock(tsk);
++		return;
++	}
++	task_unlock(tsk);
 +
-+		/*
-+		 * Now clear out our list and clean up our data structures.
-+		 * The task_lock protects our list structure.
-+		 */
-+		task_lock(tsk);
-+		list_for_each_entry_safe(state, next, &tsk->ptracees, entry) {
-+			list_del_rcu(&state->entry);
++restart:
++	rcu_read_lock();
++
++	list_for_each_safe_rcu(pos, n, &tsk->ptracees) {
++		struct ptrace_state *state = list_entry(pos,
++							struct ptrace_state,
++							entry);
++		int error = utrace_detach(state->task, state->engine);
++		BUG_ON(state->parent != tsk);
++		if (likely(error == 0)) {
++			ptrace_state_unlink(state);
 +			ptrace_done(state);
 +		}
-+		task_unlock(tsk);
++		else if (unlikely(error == -EALREADY)) {
++			/*
++			 * It's still doing report_death callbacks.
++			 * Just wait for it to settle down.
++			 * Since wait_task_inactive might yield,
++			 * we must go out of rcu_read_lock and restart.
++			 */
++			struct task_struct *p = state->task;
++			get_task_struct(p);
++			rcu_read_unlock();
++			wait_task_inactive(p);
++			put_task_struct(p);
++			goto restart;
++		}
++		else
++			BUG_ON(error != -ESRCH);
 +	}
++
 +	rcu_read_unlock();
 +
 +	BUG_ON(!list_empty(&tsk->ptracees));
@@ -6303,15 +6399,15 @@
 +		else
 +			ret = (*regset->set)(target, regset,
 +					     offset, size, NULL, data);
- 	}
--	return copied;
++	}
 +	else {
 +		if (!access_ok(VERIFY_WRITE, data, size))
 +			ret = -EIO;
 +		else
 +			ret = (*regset->get)(target, regset,
 +					     offset, size, NULL, data);
-+	}
+ 	}
+-	return copied;
 +
 +	return ret;
  }
@@ -6329,12 +6425,15 @@
 +							   view, setno);
 +	unsigned int pos;
 +	int ret;
++
++	if (unlikely(regset == NULL))
++		return -EIO;
  
 -	while (len > 0) {
 -		char buf[128];
 -		int this_len, retval;
-+	if (unlikely(regset == NULL))
-+		return -EIO;
++	if (regno < regset->bias || regno >= regset->bias + regset->n)
++		return -EINVAL;
  
 -		this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
 -		if (copy_from_user(buf, src, this_len))
@@ -6349,9 +6448,6 @@
 -		src += retval;
 -		dst += retval;
 -		len -= retval;			
-+	if (regno < regset->bias || regno >= regset->bias + regset->n)
-+		return -EINVAL;
-+
 +	pos = (regno - regset->bias) * regset->size;
 +
 +	if (write) {
@@ -6360,15 +6456,15 @@
 +		else
 +			ret = (*regset->set)(target, regset, pos, regset->size,
 +					     NULL, data);
-+	}
+ 	}
+-	return copied;
 +	else {
 +		if (!access_ok(VERIFY_WRITE, data, regset->size))
 +			ret = -EIO;
 +		else
 +			ret = (*regset->get)(target, regset, pos, regset->size,
 +					     NULL, data);
- 	}
--	return copied;
++	}
 +
 +	return ret;
  }
@@ -6536,34 +6632,30 @@
 -			error = 0;
 -		}
 -		spin_unlock_irq(&child->sighand->siglock);
++	rcu_read_lock();
 +	engine = utrace_attach(child, UTRACE_ATTACH_MATCH_OPS,
 +			       &ptrace_utrace_ops, 0);
 +	ret = -ESRCH;
 +	if (IS_ERR(engine) || engine == NULL)
-+		goto out_tsk;
-+	rcu_read_lock();
++		goto out_tsk_rcu;
 +	state = rcu_dereference((struct ptrace_state *) engine->data);
-+	if (state == NULL || state->parent != current) {
-+		rcu_read_unlock();
-+		goto out_tsk;
- 	}
--	read_unlock(&tasklist_lock);
--	return error;
++	if (state == NULL || state->parent != current)
++		goto out_tsk_rcu;
 +	rcu_read_unlock();
 +
 +	/*
 +	 * Traditional ptrace behavior demands that the target already be
 +	 * quiescent, but not dead.
 +	 */
-+	if (request != PTRACE_KILL && !state->u.live.stopped) {
++	if (request != PTRACE_KILL
++	    && !(engine->flags & UTRACE_ACTION_QUIESCE)) {
 +#ifdef PTRACE_DEBUG
 +		printk("%d not stopped (%lx)\n", child->pid, child->state);
 +#endif
-+		if (child->state != TASK_STOPPED)
-+			goto out_tsk;
-+		utrace_set_flags(child, engine,
-+				 engine->flags | UTRACE_ACTION_QUIESCE);
-+	}
++		goto out_tsk;
+ 	}
+-	read_unlock(&tasklist_lock);
+-	return error;
 +
 +	/*
 +	 * We do this for all requests to match traditional ptrace behavior.
@@ -6587,6 +6679,8 @@
 +	*statep = state;
 +	return -EIO;
 +
++out_tsk_rcu:
++	rcu_read_unlock();
 +out_tsk:
 +	put_task_struct(child);
 +out:
@@ -6698,7 +6792,7 @@
 +		if (ret)
 +			BUG_ON(ret != -ESRCH);
 +		ret = 0;
- 		break;
++		break;
 +	}
 +
 +	return ret;
@@ -6755,7 +6849,7 @@
 +		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
 +			break;
 +		ret = -EIO;
-+		break;
+ 		break;
 +
  	case PTRACE_GETEVENTMSG:
 -		ret = put_user(child->ptrace_message, (unsigned long __user *) data);
@@ -6787,7 +6881,7 @@
 +	put_task_struct(child);
 +out:
 +#ifdef PTRACE_DEBUG
-+	printk("%d ptrace -> %x\n", current->pid, ret);
++	printk("%d ptrace -> %lx\n", current->pid, ret);
 +#endif
 +	return ret;
 +}
@@ -6875,34 +6969,108 @@
 +	put_task_struct(child);
 +out:
 +#ifdef PTRACE_DEBUG
-+	printk("%d ptrace -> %x\n", current->pid, ret);
++	printk("%d ptrace -> %lx\n", current->pid, ret);
 +#endif
  	return ret;
  }
 +#endif
-+
  
 -/**
 - * ptrace_traceme  --  helper for PTRACE_TRACEME
 - *
 - * Performs checks and sets PT_PTRACED.
 - * Should be used by all ptrace implementations for PTRACE_TRACEME.
++
++/*
++ * Detach the zombie being reported for wait.
+  */
+-int ptrace_traceme(void)
++static inline void
++detach_zombie(struct task_struct *tsk,
++	      struct task_struct *p, struct ptrace_state *state)
+ {
+-	int ret = -EPERM;
+-
+-	/*
+-	 * Are we already being traced?
+-	 */
+-	task_lock(current);
+-	if (!(current->ptrace & PT_PTRACED)) {
+-		ret = security_ptrace(current->parent, current);
++	int detach_error;
++restart:
++	detach_error = 0;
++	rcu_read_lock();
++	if (tsk != current) {
+ 		/*
+-		 * Set the ptrace bit in the process ptrace flags.
++		 * We've excluded other ptrace_do_wait calls.  But the
++		 * ptracer itself might have done ptrace_detach while we
++		 * did not have rcu_read_lock.  So double-check that state
++		 * is still valid.
+ 		 */
+-		if (!ret)
+-			current->ptrace |= PT_PTRACED;
++		struct utrace_attached_engine *engine;
++		engine = utrace_attach(
++			p, (UTRACE_ATTACH_MATCH_OPS
++			    | UTRACE_ATTACH_MATCH_DATA),
++			&ptrace_utrace_ops,
++			(unsigned long) state);
++		if (IS_ERR(engine) || state->parent != tsk)
++			detach_error = -ESRCH;
++		else
++			BUG_ON(state->engine != engine);
+ 	}
+-	task_unlock(current);
+-	return ret;
++	if (likely(!detach_error))
++		detach_error = ptrace_detach(p, state->engine);
++	if (unlikely(detach_error == -EALREADY)) {
++		/*
++		 * It's still doing report_death callbacks.
++		 * Just wait for it to settle down.
++		 */
++		rcu_read_unlock();
++		wait_task_inactive(p); /* Might block.  */
++		goto restart;
++	}
++	/*
++	 * A failure with -ESRCH means that report_reap is
++	 * already running and will do the cleanup, or that
++	 * we lost a race with ptrace_detach in another
++	 * thread or with the automatic detach in
++	 * report_death.
++	 */
++	if (detach_error)
++		BUG_ON(detach_error != -ESRCH);
++	rcu_read_unlock();
+ }
+ 
+-/**
+- * ptrace_get_task_struct  --  grab a task struct reference for ptrace
+- * @pid:       process id to grab a task_struct reference of
+- *
+- * This function is a helper for ptrace implementations.  It checks
+- * permissions and then grabs a task struct for use of the actual
+- * ptrace implementation.
+- *
+- * Returns the task_struct for @pid or an ERR_PTR() on failure.
 +/*
 + * We're called with tasklist_lock held for reading.
 + * If we return -ECHILD or zero, next_thread(tsk) must still be valid to use.
 + * If we return another error code, or a successful PID value, we
 + * release tasklist_lock first.
   */
--int ptrace_traceme(void)
+-struct task_struct *ptrace_get_task_struct(pid_t pid)
 +int
 +ptrace_do_wait(struct task_struct *tsk,
 +	       pid_t pid, int options, struct siginfo __user *infop,
 +	       int __user *stat_addr, struct rusage __user *rusagep)
  {
--	int ret = -EPERM;
+-	struct task_struct *child;
 +	struct ptrace_state *state;
 +	struct task_struct *p;
-+	struct utrace *utrace;
 +	int err = -ECHILD;
 +	int exit_code, why, status;
 +
@@ -6926,34 +7094,60 @@
 +		if (security_task_wait(p))
 +			continue;
 +
++		/*
++		 * This is a matching child.  If we don't win now, tell
++		 * our caller to block and repeat.  From this point we
++		 * must ensure that wait_chldexit will get a wakeup for
++		 * any tracee stopping, dying, or being detached.
++		 * For death, tasklist_lock guarantees this already.
++		 */
 +		err = 0;
-+		if (state->u.live.reported)
-+			continue;
 +
-+		if (state->u.live.stopped)
-+			goto found;
-+		if ((p->state & (TASK_TRACED | TASK_STOPPED))
-+		    && (p->signal->flags & SIGNAL_STOP_STOPPED))
-+			goto found;
-+		if (p->exit_state == EXIT_ZOMBIE) {
++		switch (p->exit_state) {
++		case EXIT_ZOMBIE:
 +			if (!likely(options & WEXITED))
 +				continue;
 +			if (delay_group_leader(p))
 +				continue;
++			exit_code = p->exit_code;
 +			goto found;
++		case EXIT_DEAD:
++			continue;
++		default:
++			/*
++			 * tasklist_lock holds up any transitions to
++			 * EXIT_ZOMBIE.  After releasing it we are
++			 * guaranteed a wakeup on wait_chldexit after
++			 * any new deaths.
++			 */
++			break;
 +		}
++
++		/*
++		 * This xchg atomically ensures that only one do_wait
++		 * call can report this thread.  Because exit_code is
++		 * always set before do_notify wakes us up, after this
++		 * check fails we are sure to get a wakeup if it stops.
++		 */
++		exit_code = xchg(&p->exit_code, 0);
++		if (exit_code)
++			goto found;
++
 +		// XXX should handle WCONTINUED
 +	}
 +	rcu_read_unlock();
 +	return err;
 +
 +found:
++	BUG_ON(state->parent != tsk);
 +	rcu_read_unlock();
 +
-+	BUG_ON(state->parent != tsk);
++#ifdef PTRACE_DEBUG
++	printk("%d ptrace_do_wait (%d) found %d code %x (%lu)\n", current->pid, tsk->pid, p->pid, exit_code, p->exit_state);
++#endif
 +
 +	if (p->exit_state) {
-+		if (unlikely(p->parent == state->parent)) {
++		if (unlikely(p->parent == tsk))
 +			/*
 +			 * This is our natural child we were ptracing.
 +			 * When it dies it detaches (see ptrace_report_death).
@@ -6962,32 +7156,35 @@
 +			 * the normal wait_task_zombie path instead.
 +			 */
 +			return 0;
-+		}
-+		exit_code = p->exit_code;
 +		if ((exit_code & 0x7f) == 0) {
 +			why = CLD_EXITED;
 +			status = exit_code >> 8;
-+		} else {
++		}
++		else {
 +			why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED;
 +			status = exit_code & 0x7f;
 +		}
 +	}
 +	else {
 +		why = CLD_TRAPPED;
-+		status = p->exit_code;
++		status = exit_code;
 +		exit_code = (status << 8) | 0x7f;
 +	}
  
  	/*
--	 * Are we already being traced?
+-	 * Tracing init is not allowed.
 +	 * At this point we are committed to a successful return
 +	 * or a user error return.  Release the tasklist_lock.
  	 */
--	task_lock(current);
--	if (!(current->ptrace & PT_PTRACED)) {
--		ret = security_ptrace(current->parent, current);
+-	if (pid == 1)
+-		return ERR_PTR(-EPERM);
++	get_task_struct(p);
 +	read_unlock(&tasklist_lock);
-+
+ 
+-	read_lock(&tasklist_lock);
+-	child = find_task_by_pid(pid);
+-	if (child)
+-		get_task_struct(child);
 +	if (rusagep)
 +		err = getrusage(p, RUSAGE_BOTH, rusagep);
 +	if (infop) {
@@ -7006,86 +7203,34 @@
 +	}
 +	if (!err && stat_addr)
 +		err = put_user(exit_code, stat_addr);
-+
+ 
+-	read_unlock(&tasklist_lock);
+-	if (!child)
+-		return ERR_PTR(-ESRCH);
+-	return child;
 +	if (!err) {
-+
-+		err = p->pid;
-+
- 		/*
--		 * Set the ptrace bit in the process ptrace flags.
-+		 * If this was a non-death report, the child might now be
-+		 * detaching on death in the same race possible in the
-+		 * p->exit_state check above.  So check for p->utrace being
-+		 * NULL, then we don't need to update the state any more.
- 		 */
--		if (!ret)
--			current->ptrace |= PT_PTRACED;
-+		rcu_read_lock();
-+		utrace = rcu_dereference(p->utrace);
-+		if (likely(utrace != NULL)) {
-+			utrace_lock(utrace);
-+			if (unlikely(rcu_dereference(p->utrace) != utrace)
-+			    || unlikely(state->u.live.reported))
-+				/*
-+				 * Another thread in the group got here
-+				 * first and reaped it before we locked.
-+				 */
-+				err = -ERESTARTNOINTR;
-+			else
-+				state->u.live.reported = 1;
-+			utrace_unlock(utrace);
-+		}
-+
-+		if (err > 0 && why != CLD_TRAPPED) {
++		if (why != CLD_TRAPPED)
 +			/*
 +			 * This was a death report.  The ptracer's wait
 +			 * does an implicit detach, so the zombie reports
 +			 * to its real parent now.
 +			 */
-+			int detach_error = ptrace_detach(p, state->engine);
-+			while (detach_error == -EALREADY) {
-+				/*
-+				 * It's still doing report_death callbacks.
-+				 * Just wait for it to settle down.
-+				 */
-+				wait_task_inactive(p);
-+				detach_error = ptrace_detach(p, state->engine);
-+			}
-+			/*
-+			 * A failure with -ESRCH means that report_reap is
-+			 * already running and will do the cleanup, or that
-+			 * we lost a race with ptrace_detach in another
-+			 * thread or with the automatic detach in
-+			 * report_death.
-+			 */
-+			if (detach_error) {
-+				BUG_ON(detach_error != -ESRCH);
-+				err = -ERESTARTNOINTR;
-+			}
-+		}
-+		rcu_read_unlock();
- 	}
--	task_unlock(current);
--	return ret;
++			detach_zombie(tsk, p, state);
++		err = p->pid;
++	}
++
++	put_task_struct(p);
 +
 +	return err;
  }
  
--/**
-- * ptrace_get_task_struct  --  grab a task struct reference for ptrace
-- * @pid:       process id to grab a task_struct reference of
-- *
-- * This function is a helper for ptrace implementations.  It checks
-- * permissions and then grabs a task struct for use of the actual
-- * ptrace implementation.
-- *
-- * Returns the task_struct for @pid or an ERR_PTR() on failure.
-- */
--struct task_struct *ptrace_get_task_struct(pid_t pid)
+-#ifndef __ARCH_SYS_PTRACE
+-asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
 +static void
 +do_notify(struct task_struct *tsk, struct task_struct *parent, int why)
  {
 -	struct task_struct *child;
+-	long ret;
 +	struct siginfo info;
 +	unsigned long flags;
 +	struct sighand_struct *sighand;
@@ -7125,33 +7270,20 @@
 +	    !(sighand->action[SIGCHLD-1].sa.sa_flags & sa_mask))
 +		__group_send_sig_info(SIGCHLD, &info, parent);
  	/*
--	 * Tracing init is not allowed.
+-	 * This lock_kernel fixes a subtle race with suid exec
 +	 * Even if SIGCHLD is not generated, we must wake up wait4 calls.
  	 */
--	if (pid == 1)
--		return ERR_PTR(-EPERM);
--
--	read_lock(&tasklist_lock);
--	child = find_task_by_pid(pid);
--	if (child)
--		get_task_struct(child);
--
--	read_unlock(&tasklist_lock);
--	if (!child)
--		return ERR_PTR(-ESRCH);
--	return child;
+-	lock_kernel();
+-	if (request == PTRACE_TRACEME) {
+-		ret = ptrace_traceme();
 +	wake_up_interruptible_sync(&parent->signal->wait_chldexit);
 +	spin_unlock_irqrestore(&sighand->siglock, flags);
- }
- 
--#ifndef __ARCH_SYS_PTRACE
--asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
++}
++
 +static u32
 +ptrace_report(struct utrace_attached_engine *engine, struct task_struct *tsk,
 +	      int code)
- {
--	struct task_struct *child;
--	long ret;
++{
 +	struct ptrace_state *state = (struct ptrace_state *) engine->data;
 +	const struct utrace_regset *regset;
 +
@@ -7169,29 +7301,24 @@
 +
 +	/*
 +	 * Set our QUIESCE flag right now, before notifying the tracer.
-+	 * We do this before setting state->u.live.stopped rather than
++	 * We do this before setting tsk->exit_code rather than
 +	 * by using UTRACE_ACTION_NEWSTATE in our return value, to
 +	 * ensure that the tracer can't get the notification and then
 +	 * try to resume us with PTRACE_CONT before we set the flag.
 +	 */
 +	utrace_set_flags(tsk, engine, engine->flags | UTRACE_ACTION_QUIESCE);
- 
- 	/*
--	 * This lock_kernel fixes a subtle race with suid exec
++
++	/*
 +	 * If regset 0 has a writeback call, do it now.  On register window
 +	 * machines, this makes sure the user memory backing the register
 +	 * data is up to date by the time wait_task_inactive returns to
 +	 * ptrace_start in our tracer doing a PTRACE_PEEKDATA or the like.
- 	 */
--	lock_kernel();
--	if (request == PTRACE_TRACEME) {
--		ret = ptrace_traceme();
++	 */
 +	regset = utrace_regset(tsk, engine, utrace_native_view(tsk), 0);
 +	if (regset->writeback)
 +		(*regset->writeback)(tsk, regset, 0);
 +
-+	state->u.live.stopped = 1;
-+	state->u.live.reported = 0;
++	BUG_ON(code == 0);
 +	tsk->exit_code = code;
 +	do_notify(tsk, state->parent, CLD_TRAPPED);
 +
@@ -7219,6 +7346,14 @@
 +{
 +	struct ptrace_state *state = (struct ptrace_state *) engine->data;
 +
++	if (tsk->exit_code == 0 && unlikely(tsk->flags & PF_SIGNALED))
++		/*
++		 * This can only mean that tsk->exit_code was clobbered
++		 * by ptrace_update or ptrace_do_wait in a race with
++		 * an asynchronous wakeup and exit for SIGKILL.
++		 */
++		tsk->exit_code = SIGKILL;
++
 +	if (tsk->parent == state->parent) {
 +		/*
 +		 * This is a natural child, so we detach and let the normal
@@ -7234,7 +7369,6 @@
 +		return UTRACE_ACTION_DETACH;
 +	}
 +
-+	state->u.live.reported = 0;
 +	do_notify(tsk, state->parent, CLD_EXITED);
 +	return UTRACE_ACTION_RESUME;
 +}
@@ -7303,18 +7437,21 @@
 +		       child->pid, parent->pid);
 +	}
 +	else {
-+		int ret = ptrace_setup(child, child_engine,
-+				       state->parent,
-+				       state->u.live.options,
-+				       state->u.live.cap_sys_ptrace);
-+		if (unlikely(ret != 0)) {
-+			BUG_ON(ret != -ENOMEM);
++		struct ptrace_state *child_state;
++		child_state = ptrace_setup(child, child_engine,
++					   state->parent,
++					   state->u.live.options,
++					   state->u.live.cap_sys_ptrace,
++					   NULL);
++		if (unlikely(IS_ERR(child_state))) {
++			BUG_ON(PTR_ERR(child_state) != -ENOMEM);
++			(void) utrace_detach(child, child_engine);
 +			printk(KERN_ERR
 +			       "ptrace out of memory, lost child %d of %d",
 +			       child->pid, parent->pid);
-+			utrace_detach(child, child_engine);
 +		}
 +		else {
++			int ret;
 +			sigaddset(&child->pending.signal, SIGSTOP);
 +			set_tsk_thread_flag(child, TIF_SIGPENDING);
 +			ret = ptrace_update(child, child_engine, 0);
@@ -7359,8 +7496,7 @@
 +	state->u.live.have_eventmsg = 1;
 +	state->u.live.u.eventmsg = child_pid;
 +	return ptrace_event(engine, parent, PTRACE_EVENT_VFORK_DONE);
- }
--#endif /* __ARCH_SYS_PTRACE */
++}
 +
 +
 +static u32
@@ -7387,7 +7523,6 @@
 +	printk("ptrace %d jctl notify %d type %x exit_code %x\n",
 +	       tsk->pid, state->parent->pid, type, tsk->exit_code);
 +#endif
-+	state->u.live.reported = 0;
 +	do_notify(tsk, state->parent, type);
 +	return UTRACE_JCTL_NOSIGCHLD;
 +}
@@ -7426,7 +7561,8 @@
 +			    struct task_struct *tsk, struct pt_regs *regs)
 +{
 +	return ptrace_report_syscall(engine, tsk, regs, 1);
-+}
+ }
+-#endif /* __ARCH_SYS_PTRACE */
 +
 +static u32
 +ptrace_report_syscall_exit(struct utrace_attached_engine *engine,
@@ -7517,7 +7653,7 @@
 +#endif
 --- linux-2.6/kernel/Makefile.utrace-ptrace-compat
 +++ linux-2.6/kernel/Makefile
-@@ -51,6 +51,7 @@ obj-$(CONFIG_RELAY) += relay.o
+@@ -50,6 +50,7 @@ obj-$(CONFIG_RELAY) += relay.o
  obj-$(CONFIG_UTS_NS) += utsname.o
  obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
  obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
@@ -9981,7 +10117,7 @@
  /*
   * Note: it is necessary to treat pid and sig as unsigned ints, with the
   * corresponding cast to a signed int to insure that the proper conversion
-@@ -1216,6 +1269,8 @@ no_signal:
+@@ -1226,6 +1279,8 @@ no_signal:
  		   its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
  		if (test_thread_flag(TIF_RESTORE_SIGMASK))
  			clear_thread_flag(TIF_RESTORE_SIGMASK);
@@ -16506,7 +16642,7 @@
  }
 --- linux-2.6/arch/x86_64/kernel/traps.c.utrace-ptrace-compat
 +++ linux-2.6/arch/x86_64/kernel/traps.c
-@@ -930,14 +930,6 @@ asmlinkage void __kprobes do_debug(struc
+@@ -864,14 +864,6 @@ asmlinkage void __kprobes do_debug(struc
  		 */
                  if (!user_mode(regs))
                         goto clear_TF_reenable;




More information about the fedora-cvs-commits mailing list