rpms/kernel/F-10 linux-2.6-ptrace-fix-possible-zombie-leak.patch, NONE, 1.1 kernel.spec, 1.1375, 1.1376 linux-2.6-tracehook.patch, 1.8, 1.9 linux-2.6-utrace.patch, 1.109, 1.110

Chuck Ebbert cebbert at fedoraproject.org
Wed Jun 3 03:00:21 UTC 2009


Author: cebbert

Update of /cvs/pkgs/rpms/kernel/F-10
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv23501

Modified Files:
	kernel.spec linux-2.6-tracehook.patch linux-2.6-utrace.patch 
Added Files:
	linux-2.6-ptrace-fix-possible-zombie-leak.patch 
Log Message:
Fix F11 bug #481753: ptraced processes fail to deliver exit notification
Copy utrace update from F-11

linux-2.6-ptrace-fix-possible-zombie-leak.patch:

--- NEW FILE linux-2.6-ptrace-fix-possible-zombie-leak.patch ---
ptrace: fix possible zombie leak on PTRACE_DETACH

Rollup of:

http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=95c3eb76dc07fd81289888ffc42948196b34b444
ptrace: kill __ptrace_detach(), fix ->exit_state check

http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=6d69cb87f05eef3b02370b2f7bae608ad2301a00
ptrace: simplify ptrace_exit()->ignoring_children() path

http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=b1b4c6799fb59e710454bfe0ab477cb8523a8667
ptrace: reintroduce __ptrace_detach() as a callee of ptrace_exit()

http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=4576145c1ecdaaea9ef8976a48335206aa1ebf91
ptrace: fix possible zombie leak on PTRACE_DETACH

--- work-2.6.29.4.orig/kernel/ptrace.c
+++ work-2.6.29.4/kernel/ptrace.c
@@ -235,18 +235,10 @@ out:
 	return retval;
 }
 
-static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
-{
-	child->exit_code = data;
-	/* .. re-parent .. */
-	__ptrace_unlink(child);
-	/* .. and wake it up. */
-	if (child->exit_state != EXIT_ZOMBIE)
-		wake_up_process(child);
-}
-
 int ptrace_detach(struct task_struct *child, unsigned int data)
 {
+	int dead = 0;
+
 	if (!valid_signal(data))
 		return -EIO;
 
@@ -256,10 +248,19 @@ int ptrace_detach(struct task_struct *ch
 
 	write_lock_irq(&tasklist_lock);
 	/* protect against de_thread()->release_task() */
-	if (child->ptrace)
-		__ptrace_detach(child, data);
+	if (child->ptrace) {
+		child->exit_code = data;
+
+		dead = __ptrace_detach(current, child);
+
+		if (!child->exit_state)
+			wake_up_process(child);
+	}
 	write_unlock_irq(&tasklist_lock);
 
+	if (unlikely(dead))
+		release_task(child);
+
 	return 0;
 }
 
--- work-2.6.29.4.orig/kernel/exit.c
+++ work-2.6.29.4/kernel/exit.c
@@ -703,22 +703,50 @@ static void exit_mm(struct task_struct *
 }
 
 /*
- * Return nonzero if @parent's children should reap themselves.
- *
- * Called with write_lock_irq(&tasklist_lock) held.
+ * Called with irqs disabled, returns true if childs should reap themselves.
  */
-static int ignoring_children(struct task_struct *parent)
+static int ignoring_children(struct sighand_struct *sigh)
 {
 	int ret;
-	struct sighand_struct *psig = parent->sighand;
-	unsigned long flags;
-	spin_lock_irqsave(&psig->siglock, flags);
-	ret = (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
-	       (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT));
-	spin_unlock_irqrestore(&psig->siglock, flags);
+	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;
 }
 
+/* Returns nonzero if the tracee should be released. */
+int __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
+{
+	__ptrace_unlink(p);
+
+	if (p->exit_state != EXIT_ZOMBIE)
+		return 0;
+	/*
+	 * 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 we 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.
+	 */
+	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))
+			p->exit_signal = -1;
+	}
+
+	if (!task_detached(p))
+		return 0;
+
+	/* Mark it as in the process of being reaped. */
+	p->exit_state = EXIT_DEAD;
+	return 1;
+}
+
 /*
  * Detach all tasks we were using ptrace on.
  * Any that need to be release_task'd are put on the @dead list.
@@ -728,43 +756,10 @@ static int ignoring_children(struct task
 static void ptrace_exit(struct task_struct *parent, struct list_head *dead)
 {
 	struct task_struct *p, *n;
-	int ign = -1;
 
 	list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) {
-		__ptrace_unlink(p);
-
-		if (p->exit_state != EXIT_ZOMBIE)
-			continue;
-
-		/*
-		 * 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, add it to the @dead list.  We can't call
-		 * release_task() here because we already hold tasklist_lock.
-		 *
-		 * 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.
-		 */
-		if (!task_detached(p) && thread_group_empty(p)) {
-			if (!same_thread_group(p->real_parent, parent))
-				do_notify_parent(p, p->exit_signal);
-			else {
-				if (ign < 0)
-					ign = ignoring_children(parent);
-				if (ign)
-					p->exit_signal = -1;
-			}
-		}
-
-		if (task_detached(p)) {
-			/*
-			 * Mark it as in the process of being reaped.
-			 */
-			p->exit_state = EXIT_DEAD;
+		if (__ptrace_detach(parent, p))
 			list_add(&p->ptrace_entry, dead);
-		}
 	}
 }
 
--- work-2.6.29.4.orig/include/linux/ptrace.h
+++ work-2.6.29.4/include/linux/ptrace.h
@@ -94,6 +94,7 @@ extern void ptrace_notify(int exit_code)
 extern void __ptrace_link(struct task_struct *child,
 			  struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
+extern int __ptrace_detach(struct task_struct *tracer, struct task_struct *p);
 extern void ptrace_fork(struct task_struct *task, unsigned long clone_flags);
 #define PTRACE_MODE_READ   1
 #define PTRACE_MODE_ATTACH 2


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-10/kernel.spec,v
retrieving revision 1.1375
retrieving revision 1.1376
diff -u -p -r1.1375 -r1.1376
--- kernel.spec	25 May 2009 19:06:16 -0000	1.1375
+++ kernel.spec	3 Jun 2009 02:59:49 -0000	1.1376
@@ -589,6 +589,8 @@ Patch20: linux-2.6-hotfixes.patch
 Patch21: linux-2.6-tracehook.patch
 Patch22: linux-2.6-utrace.patch
 Patch23: linux-2.6-utrace-ftrace.patch
+# bz #481753: ptraced processes fail to deliver exit notification
+Patch24: linux-2.6-ptrace-fix-possible-zombie-leak.patch
 
 # Support suspend/resume, other crash fixes
 Patch30: linux-2.6-iommu-fixes.patch
@@ -1163,6 +1165,8 @@ ApplyPatch linux-2.6-hotfixes.patch
 ApplyPatch linux-2.6-tracehook.patch
 ApplyPatch linux-2.6-utrace.patch
 ApplyPatch linux-2.6-utrace-ftrace.patch
+# bz #481753
+ApplyPatch linux-2.6-ptrace-fix-possible-zombie-leak.patch
 
 # IOMMU fixes backported to 2.6.29
 ApplyPatch linux-2.6-iommu-fixes.patch
@@ -1984,6 +1988,10 @@ fi
 %kernel_variant_files -k vmlinux %{with_kdump} kdump
 
 %changelog
+* Tue Jun 02 2009 Chuck Ebbert <cebbert at redhat.com> 2.6.29.4-76
+- Fix F11 bug #481753: ptraced processes fail to deliver exit notification
+- Copy utrace update from F-11
+
 * Mon May 25 2009 Chuck Ebbert <cebbert at redhat.com> 2.6.29.4-75
 - Fix oops in keyring code (F11#501588)
 

linux-2.6-tracehook.patch:

Index: linux-2.6-tracehook.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-10/linux-2.6-tracehook.patch,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -p -r1.8 -r1.9
--- linux-2.6-tracehook.patch	19 Mar 2009 18:43:01 -0000	1.8
+++ linux-2.6-tracehook.patch	3 Jun 2009 02:59:50 -0000	1.9
@@ -70,7 +70,7 @@ index 6186a78..b622498 100644  
  
  #define DEATH_REAP			-1
 diff --git a/kernel/signal.c b/kernel/signal.c
-index 2a74fe8..9a0d98f 100644  
+index 1c88144..1adbb90 100644  
 --- a/kernel/signal.c
 +++ b/kernel/signal.c
 @@ -691,7 +691,7 @@ static int prepare_signal(int sig, struc
@@ -82,7 +82,7 @@ index 2a74fe8..9a0d98f 100644  
  			 * will take ->siglock, notice SIGNAL_CLD_MASK, and
  			 * notify its parent. See get_signal_to_deliver().
  			 */
-@@ -1629,29 +1629,6 @@ void ptrace_notify(int exit_code)
+@@ -1637,29 +1637,6 @@ void ptrace_notify(int exit_code)
  	spin_unlock_irq(&current->sighand->siglock);
  }
  
@@ -112,7 +112,7 @@ index 2a74fe8..9a0d98f 100644  
  /*
   * This performs the stopping for SIGSTOP and other stop signals.
   * We have to stop all threads in the thread group.
-@@ -1662,6 +1639,7 @@ static int do_signal_stop(int signr)
+@@ -1670,6 +1647,7 @@ static int do_signal_stop(int signr)
  {
  	struct signal_struct *sig = current->signal;
  	int stop_count;
@@ -120,7 +120,7 @@ index 2a74fe8..9a0d98f 100644  
  
  	if (sig->group_stop_count > 0) {
  		/*
-@@ -1701,8 +1679,30 @@ static int do_signal_stop(int signr)
+@@ -1709,8 +1687,30 @@ static int do_signal_stop(int signr)
  	current->exit_code = sig->group_exit_code;
  	__set_current_state(TASK_STOPPED);
  
@@ -152,7 +152,7 @@ index 2a74fe8..9a0d98f 100644  
  	return 1;
  }
  
-@@ -1771,14 +1771,15 @@ relock:
+@@ -1779,14 +1779,15 @@ relock:
  		int why = (signal->flags & SIGNAL_STOP_CONTINUED)
  				? CLD_CONTINUED : CLD_STOPPED;
  		signal->flags &= ~SIGNAL_CLD_MASK;
@@ -174,7 +174,7 @@ index 2a74fe8..9a0d98f 100644  
  		goto relock;
  	}
  
-@@ -1936,14 +1937,14 @@ void exit_signals(struct task_struct *ts
+@@ -1944,14 +1945,14 @@ void exit_signals(struct task_struct *ts
  	if (unlikely(tsk->signal->group_stop_count) &&
  			!--tsk->signal->group_stop_count) {
  		tsk->signal->flags = SIGNAL_STOP_STOPPED;

linux-2.6-utrace.patch:

Index: linux-2.6-utrace.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-10/linux-2.6-utrace.patch,v
retrieving revision 1.109
retrieving revision 1.110
diff -u -p -r1.109 -r1.110
--- linux-2.6-utrace.patch	9 May 2009 03:37:41 -0000	1.109
+++ linux-2.6-utrace.patch	3 Jun 2009 02:59:50 -0000	1.110
@@ -26,18 +26,18 @@ the utrace API.
 Signed-off-by: Roland McGrath <roland at redhat.com>
 ---
  Documentation/DocBook/Makefile    |    2 +-
- Documentation/DocBook/utrace.tmpl |  571 +++++++++
+ Documentation/DocBook/utrace.tmpl |  590 ++++++++++
  fs/proc/array.c                   |    3 +
  include/linux/init_task.h         |    1 +
  include/linux/sched.h             |    6 +
- include/linux/tracehook.h         |   50 +-
+ include/linux/tracehook.h         |   61 +-
  include/linux/utrace.h            |  692 +++++++++++
  include/linux/utrace_struct.h     |   58 +
  init/Kconfig                      |    9 +
  kernel/Makefile                   |    1 +
  kernel/ptrace.c                   |   18 +-
- kernel/utrace.c                   | 2348 +++++++++++++++++++++++++++++++++++++
- 12 files changed, 3756 insertions(+), 3 deletions(-)
+ kernel/utrace.c                   | 2357 +++++++++++++++++++++++++++++++++++++
+ 12 files changed, 3795 insertions(+), 3 deletions(-)
 
 diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
 index 1462ed8..f5da1b4 100644  
@@ -54,10 +54,10 @@ index 1462ed8..f5da1b4 100644  
  	    mac80211.xml debugobjects.xml sh.xml regulator.xml
 diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl
 new file mode 100644
-index ...b802c55 100644  
+index ...6cc58a1 100644  
 --- /dev/null
 +++ b/Documentation/DocBook/utrace.tmpl
-@@ -0,0 +1,571 @@
+@@ -0,0 +1,590 @@
 +<?xml version="1.0" encoding="UTF-8"?>
 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
 +"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
@@ -123,12 +123,12 @@ index ...b802c55 100644  
 +  <para>
 +    Many engines can be attached to each thread.  When a thread has an
 +    event, each engine gets a callback if it has set the event flag for
-+    that event type.  Engines are called in the order they attached.
-+    Engines that attach after the event has occurred do not get callbacks
-+    for that event.  This includes any new engines just attached by an
-+    existing engine's callback function.  Once the sequence of callbacks
-+    for that one event has completed, such new engines are then eligible in
-+    the next sequence that starts when there is another event.
++    that event type.  For most events, engines are called in the order they
++    attached.  Engines that attach after the event has occurred do not get
++    callbacks for that event.  This includes any new engines just attached
++    by an existing engine's callback function.  Once the sequence of
++    callbacks for that one event has completed, such new engines are then
++    eligible in the next sequence that starts when there is another event.
 +  </para>
 +
 +  <para>
@@ -146,6 +146,25 @@ index ...b802c55 100644  
 +    <function>utrace_control</function> to resume the thread.
 +  </para>
 +
++  <para>
++    The <constant>UTRACE_EVENT(SYSCALL_ENTRY)</constant> event is a special
++    case.  While other events happen in the kernel when it will return to
++    user mode soon, this event happens when entering the kernel before it
++    will proceed with the work requested from user mode.  Because of this
++    difference, the <function>report_syscall_entry</function> callback is
++    special in two ways.  For this event, engines are called in reverse of
++    the normal order (this includes the <function>report_quiesce</function>
++    call that precedes a <function>report_syscall_entry</function> call).
++    This preserves the semantics that the last engine to attach is called
++    "closest to user mode"--the engine that is first to see a thread's user
++    state when it enters the kernel is also the last to see that state when
++    the thread returns to user mode.  For the same reason, if these
++    callbacks use <constant>UTRACE_STOP</constant> (see the next section),
++    the thread stops immediately after callbacks rather than only when it's
++    ready to return to user mode; when allowed to resume, it will actually
++    attempt the system call indicated by the register values at that time.
++  </para>
++
 +  </sect1>
 +
 +  <sect1 id="safely"><title>Stopping Safely</title>
@@ -630,10 +649,10 @@ index ...b802c55 100644  
 +
 +</book>
 diff --git a/fs/proc/array.c b/fs/proc/array.c
-index 7e4877d..0c683ed 100644  
+index 725a650..e299a63 100644  
 --- a/fs/proc/array.c
 +++ b/fs/proc/array.c
-@@ -81,6 +81,7 @@
+@@ -82,6 +82,7 @@
  #include <linux/pid_namespace.h>
  #include <linux/ptrace.h>
  #include <linux/tracehook.h>
@@ -641,7 +660,7 @@ index 7e4877d..0c683ed 100644  
  
  #include <asm/pgtable.h>
  #include <asm/processor.h>
-@@ -187,6 +188,8 @@ static inline void task_state(struct seq
+@@ -188,6 +189,8 @@ static inline void task_state(struct seq
  		cred->uid, cred->euid, cred->suid, cred->fsuid,
  		cred->gid, cred->egid, cred->sgid, cred->fsgid);
  
@@ -663,7 +682,7 @@ index e752d97..39eebc8 100644  
  	INIT_TRACE_IRQFLAGS						\
  	INIT_LOCKDEP							\
 diff --git a/include/linux/sched.h b/include/linux/sched.h
-index 011db2f..786ef2d 100644  
+index f8af167..454de2a 100644  
 --- a/include/linux/sched.h
 +++ b/include/linux/sched.h
 @@ -59,6 +59,7 @@ struct sched_param {
@@ -674,7 +693,7 @@ index 011db2f..786ef2d 100644  
  
  #include <asm/system.h>
  #include <asm/page.h>
-@@ -1287,6 +1288,11 @@ struct task_struct {
+@@ -1288,6 +1289,11 @@ struct task_struct {
  #endif
  	seccomp_t seccomp;
  
@@ -687,7 +706,7 @@ index 011db2f..786ef2d 100644  
     	u32 parent_exec_id;
     	u32 self_exec_id;
 diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index b622498..6ff7277 100644  
+index b622498..8def62a 100644  
 --- a/include/linux/tracehook.h
 +++ b/include/linux/tracehook.h
 @@ -49,6 +49,7 @@
@@ -851,17 +870,28 @@ index b622498..6ff7277 100644  
  	if (task->exit_signal == -1)
  		return task->ptrace ? SIGCHLD : DEATH_REAP;
  
-@@ -550,6 +585,9 @@ static inline void tracehook_report_deat
+@@ -550,6 +585,20 @@ static inline void tracehook_report_deat
  					  int signal, void *death_cookie,
  					  int group_dead)
  {
++	/*
++	 * This barrier ensures that our caller's setting of
++	 * @task->exit_state precedes checking @task->utrace_flags here.
++	 * If utrace_set_events() was just called to enable
++	 * UTRACE_EVENT(DEATH), then we are obliged to call
++	 * utrace_report_death() and not miss it.  utrace_set_events()
++	 * uses tasklist_lock to synchronize enabling the bit with the
++	 * actual change to @task->exit_state, but we need this barrier
++	 * to be sure we see a flags change made just before our caller
++	 * took the tasklist_lock.
++	 */
 +	smp_mb();
 +	if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS)
 +		utrace_report_death(task, death_cookie, group_dead, signal);
  }
  
  #ifdef TIF_NOTIFY_RESUME
-@@ -579,10 +617,20 @@ static inline void set_notify_resume(str
+@@ -579,10 +628,20 @@ static inline void set_notify_resume(str
   * asynchronously, this will be called again before we return to
   * user mode.
   *
@@ -885,7 +915,7 @@ index b622498..6ff7277 100644  
  
 diff --git a/include/linux/utrace.h b/include/linux/utrace.h
 new file mode 100644
-index ...f46cc0f 100644  
+index ...f877ec6 100644  
 --- /dev/null
 +++ b/include/linux/utrace.h
 @@ -0,0 +1,692 @@
@@ -1067,7 +1097,7 @@ index ...f46cc0f 100644  
 + * that is developed concurrently with utrace API improvements before they
 + * are merged into the kernel, making LINUX_VERSION_CODE checks unwieldy.
 + */
-+#define UTRACE_API_VERSION	20090302
++#define UTRACE_API_VERSION	20090416
 +
 +/**
 + * enum utrace_resume_action - engine's choice of action for a traced task
@@ -1678,7 +1708,7 @@ index e4791b3..7bff724 100644  
  obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
  obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
 diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index c9cf48b..41e9542 100644  
+index dc3b98e..f897ef6 100644  
 --- a/kernel/ptrace.c
 +++ b/kernel/ptrace.c
 @@ -16,6 +16,7 @@
@@ -1729,10 +1759,10 @@ index c9cf48b..41e9542 100644  
  		 */
 diff --git a/kernel/utrace.c b/kernel/utrace.c
 new file mode 100644
-index ...115be79 100644  
+index ...74b5fc5 100644  
 --- /dev/null
 +++ b/kernel/utrace.c
-@@ -0,0 +1,2348 @@
+@@ -0,0 +1,2357 @@
 +/*
 + * utrace infrastructure interface for debugging user processes
 + *
@@ -1949,6 +1979,11 @@ index ...115be79 100644  
 + *
 + * UTRACE_ATTACH_MATCH_OPS: Only consider engines matching @ops.
 + * UTRACE_ATTACH_MATCH_DATA: Only consider engines matching @data.
++ *
++ * Calls with neither %UTRACE_ATTACH_MATCH_OPS nor %UTRACE_ATTACH_MATCH_DATA
++ * match the first among any engines attached to @target.  That means that
++ * %UTRACE_ATTACH_EXCLUSIVE in such a call fails with -%EEXIST if there
++ * are any engines on @target at all.
 + */
 +struct utrace_engine *utrace_attach_task(
 +	struct task_struct *target, int flags,
@@ -3181,6 +3216,7 @@ index ...115be79 100644  
 +		return ops;
 +	}
 +
++	utrace->reporting = NULL;
 +	return NULL;
 +}
 +
@@ -3192,16 +3228,16 @@ index ...115be79 100644  
 +#define REPORT(task, utrace, report, event, callback, ...)		      \
 +	do {								      \
 +		start_report(utrace);					      \
-+		REPORT_CALLBACKS(task, utrace, report, event, callback,	      \
++		REPORT_CALLBACKS(, task, utrace, report, event, callback,     \
 +				 (report)->action, engine, current,	      \
 +				 ## __VA_ARGS__);  	   		      \
 +		finish_report(report, task, utrace);			      \
 +	} while (0)
-+#define REPORT_CALLBACKS(task, utrace, report, event, callback, ...)	      \
++#define REPORT_CALLBACKS(rev, task, utrace, report, event, callback, ...)     \
 +	do {								      \
 +		struct utrace_engine *engine;				      \
 +		const struct utrace_engine_ops *ops;			      \
-+		list_for_each_entry(engine, &utrace->attached, entry) {	      \
++		list_for_each_entry##rev(engine, &utrace->attached, entry) {  \
 +			ops = start_callback(utrace, report, engine, task,    \
 +					     event);			      \
 +			if (!ops)					      \
@@ -3236,9 +3272,9 @@ index ...115be79 100644  
 +	INIT_REPORT(report);
 +
 +	start_report(utrace);
-+	REPORT_CALLBACKS(task, utrace, &report, UTRACE_EVENT(SYSCALL_ENTRY),
-+			 report_syscall_entry, report.result | report.action,
-+			 engine, current, regs);
++	REPORT_CALLBACKS(_reverse, task, utrace, &report,
++			 UTRACE_EVENT(SYSCALL_ENTRY), report_syscall_entry,
++			 report.result | report.action, engine, current, regs);
 +	finish_report(&report, task, utrace);
 +
 +	if (report.action == UTRACE_STOP &&
@@ -3249,25 +3285,7 @@ index ...115be79 100644  
 +		 */
 +		return true;
 +
-+	if (unlikely(report.result == UTRACE_SYSCALL_ABORT))
-+		return true;
-+
-+	if (signal_pending(task)) {
-+		/*
-+		 * Clear TIF_SIGPENDING if it no longer needs to be set.
-+		 * It may have been set as part of quiescence, and won't
-+		 * ever have been cleared by another thread.  For other
-+		 * reports, we can just leave it set and will go through
-+		 * utrace_get_signal() to reset things.  But here we are
-+		 * about to enter a syscall, which might bail out with an
-+		 * -ERESTART* error if it's set now.
-+		 */
-+		spin_lock_irq(&task->sighand->siglock);
-+		recalc_sigpending();
-+		spin_unlock_irq(&task->sighand->siglock);
-+	}
-+
-+	return false;
++	return report.result == UTRACE_SYSCALL_ABORT;
 +}
 +
 +/*
@@ -3304,7 +3322,7 @@ index ...115be79 100644  
 +	start_report(utrace);
 +	utrace->cloning = child;
 +
-+	REPORT_CALLBACKS(task, utrace, &report,
++	REPORT_CALLBACKS(, task, utrace, &report,
 +			 UTRACE_EVENT(CLONE), report_clone,
 +			 report.action, engine, task, clone_flags, child);
 +
@@ -3454,7 +3472,7 @@ index ...115be79 100644  
 +	utrace->interrupt = 0;
 +	spin_unlock(&utrace->lock);
 +
-+	REPORT_CALLBACKS(task, utrace, &report, UTRACE_EVENT(DEATH),
++	REPORT_CALLBACKS(, task, utrace, &report, UTRACE_EVENT(DEATH),
 +			 report_death, engine, task, group_dead, signal);
 +
 +	spin_lock(&utrace->lock);
@@ -3498,12 +3516,29 @@ index ...115be79 100644  
 +			set_tsk_thread_flag(task, TIF_SIGPENDING);
 +		break;
 +
-+	case UTRACE_SINGLESTEP:
-+		user_enable_single_step(task);
-+		break;
-+
 +	case UTRACE_BLOCKSTEP:
-+		user_enable_block_step(task);
++		if (likely(arch_has_block_step())) {
++			user_enable_block_step(task);
++			break;
++		}
++
++		/*
++		 * This means some callback is to blame for failing
++		 * to check arch_has_block_step() itself.  Warn and
++		 * then fall through to treat it as SINGLESTEP.
++		 */
++		WARN_ON(1);
++
++	case UTRACE_SINGLESTEP:
++		if (likely(arch_has_single_step()))
++			user_enable_single_step(task);
++		else
++			/*
++			 * This means some callback is to blame for failing
++			 * to check arch_has_single_step() itself.  Spew
++			 * about it so the loser will fix his module.
++			 */
++			WARN_ON(1);
 +		break;
 +
 +	case UTRACE_REPORT:
@@ -3548,11 +3583,15 @@ index ...115be79 100644  
 +	}
 +
 +	/*
-+	 * If UTRACE_INTERRUPT was just used, we don't bother with a
-+	 * report here.  We will report and stop in utrace_get_signal().
++	 * If UTRACE_INTERRUPT was just used, we don't bother with a report
++	 * here.  We will report and stop in utrace_get_signal().  In case
++	 * of a race with utrace_control(), make sure we don't momentarily
++	 * return to user mode because TIF_SIGPENDING was not set yet.
 +	 */
-+	if (unlikely(utrace->interrupt))
++	if (unlikely(utrace->interrupt)) {
++		set_thread_flag(TIF_SIGPENDING);
 +		return;
++	}
 +
 +	/*
 +	 * Do a simple reporting pass, with no callback after report_quiesce.




More information about the fedora-extras-commits mailing list