summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2014-04-13 20:58:54 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-06 18:54:16 -0700
commite6bc60b8fb412b38db86bc1351f2ce40ad31d0e0 (patch)
tree7fa6f63114bf298bebe1833f5966a5d76d6d727f
parentc5bce73649b8a164990182b46185197f3d424f41 (diff)
downloadlinux-stable-e6bc60b8fb412b38db86bc1351f2ce40ad31d0e0.tar.gz
linux-stable-e6bc60b8fb412b38db86bc1351f2ce40ad31d0e0.tar.bz2
linux-stable-e6bc60b8fb412b38db86bc1351f2ce40ad31d0e0.zip
tracing: Fix syscall_*regfunc() vs copy_process() race
commit 4af4206be2bd1933cae20c2b6fb2058dbc887f7c upstream. syscall_regfunc() and syscall_unregfunc() should set/clear TIF_SYSCALL_TRACEPOINT system-wide, but do_each_thread() can race with copy_process() and miss the new child which was not added to the process/thread lists yet. Change copy_process() to update the child's TIF_SYSCALL_TRACEPOINT under tasklist. Link: http://lkml.kernel.org/p/20140413185854.GB20668@redhat.com Fixes: a871bd33a6c0 "tracing: Add syscall tracepoints" Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--include/trace/syscall.h15
-rw-r--r--kernel/fork.c2
2 files changed, 17 insertions, 0 deletions
diff --git a/include/trace/syscall.h b/include/trace/syscall.h
index 84bc4197e736..0a5b4952aa30 100644
--- a/include/trace/syscall.h
+++ b/include/trace/syscall.h
@@ -4,6 +4,7 @@
#include <linux/tracepoint.h>
#include <linux/unistd.h>
#include <linux/ftrace_event.h>
+#include <linux/thread_info.h>
#include <asm/ptrace.h>
@@ -31,4 +32,18 @@ struct syscall_metadata {
struct ftrace_event_call *exit_event;
};
+#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS)
+static inline void syscall_tracepoint_update(struct task_struct *p)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ set_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT);
+ else
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT);
+}
+#else
+static inline void syscall_tracepoint_update(struct task_struct *p)
+{
+}
+#endif
+
#endif /* _TRACE_SYSCALL_H */
diff --git a/kernel/fork.c b/kernel/fork.c
index 270c1dab674a..814363a69b80 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1479,7 +1479,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
total_forks++;
spin_unlock(&current->sighand->siglock);
+ syscall_tracepoint_update(p);
write_unlock_irq(&tasklist_lock);
+
proc_fork_connector(p);
cgroup_post_fork(p);
if (clone_flags & CLONE_THREAD)