tracing-change-tracing_fops-snapshot_fops-to-rely-on-tracing_get_cpu.patch
ftrace-add-check-for-null-regs-if-ops-has-save_regs-set.patch
tracing-turn-event-id-i_private-into-call-event.type.patch
+tracing-change-event_enable-disable_read-to-verify-i_private-null.patch
+tracing-change-event_filter_read-write-to-verify-i_private-null.patch
+tracing-change-f_start-to-take-event_mutex-and-verify-i_private-null.patch
+tracing-introduce-remove_event_file_dir.patch
--- /dev/null
+From bc6f6b08dee5645770efb4b76186ded313f23752 Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Fri, 26 Jul 2013 19:25:36 +0200
+Subject: tracing: Change event_enable/disable_read() to verify i_private != NULL
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit bc6f6b08dee5645770efb4b76186ded313f23752 upstream.
+
+tracing_open_generic_file() is racy, ftrace_event_file can be
+already freed by rmdir or trace_remove_event_call().
+
+Change event_enable_read() and event_disable_read() to read and
+verify "file = i_private" under event_mutex.
+
+This fixes nothing, but now we can change debugfs_remove("enable")
+callers to nullify ->i_private and fix the the problem.
+
+Link: http://lkml.kernel.org/r/20130726172536.GA3612@redhat.com
+
+Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.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>
+
+
+---
+ kernel/trace/trace_events.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -682,13 +682,23 @@ static ssize_t
+ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+ {
+- struct ftrace_event_file *file = filp->private_data;
++ struct ftrace_event_file *file;
++ unsigned long flags;
+ char *buf;
+
+- if (file->flags & FTRACE_EVENT_FL_ENABLED) {
+- if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)
++ mutex_lock(&event_mutex);
++ file = event_file_data(filp);
++ if (likely(file))
++ flags = file->flags;
++ mutex_unlock(&event_mutex);
++
++ if (!file)
++ return -ENODEV;
++
++ if (flags & FTRACE_EVENT_FL_ENABLED) {
++ if (flags & FTRACE_EVENT_FL_SOFT_DISABLED)
+ buf = "0*\n";
+- else if (file->flags & FTRACE_EVENT_FL_SOFT_MODE)
++ else if (flags & FTRACE_EVENT_FL_SOFT_MODE)
+ buf = "1*\n";
+ else
+ buf = "1\n";
+@@ -702,13 +712,10 @@ static ssize_t
+ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+ {
+- struct ftrace_event_file *file = filp->private_data;
++ struct ftrace_event_file *file;
+ unsigned long val;
+ int ret;
+
+- if (!file)
+- return -EINVAL;
+-
+ ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+ if (ret)
+ return ret;
+@@ -720,8 +727,11 @@ event_enable_write(struct file *filp, co
+ switch (val) {
+ case 0:
+ case 1:
++ ret = -ENODEV;
+ mutex_lock(&event_mutex);
+- ret = ftrace_event_enable_disable(file, val);
++ file = event_file_data(filp);
++ if (likely(file))
++ ret = ftrace_event_enable_disable(file, val);
+ mutex_unlock(&event_mutex);
+ break;
+
--- /dev/null
+From e2912b091c26b8ea95e5e00a43a7ac620f6c94a6 Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Fri, 26 Jul 2013 19:25:40 +0200
+Subject: tracing: Change event_filter_read/write to verify i_private != NULL
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit e2912b091c26b8ea95e5e00a43a7ac620f6c94a6 upstream.
+
+event_filter_read/write() are racy, ftrace_event_call can be already
+freed by trace_remove_event_call() callers.
+
+1. Shift mutex_lock(event_mutex) from print/apply_event_filter to
+ the callers.
+
+2. Change the callers, event_filter_read() and event_filter_write()
+ to read i_private under this mutex and abort if it is NULL.
+
+This fixes nothing, but now we can change debugfs_remove("filter")
+callers to nullify ->i_private and fix the the problem.
+
+Link: http://lkml.kernel.org/r/20130726172540.GA3619@redhat.com
+
+Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.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>
+
+
+---
+ kernel/trace/trace_events.c | 26 +++++++++++++++++++-------
+ kernel/trace/trace_events_filter.c | 17 ++++++-----------
+ 2 files changed, 25 insertions(+), 18 deletions(-)
+
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -1002,21 +1002,28 @@ static ssize_t
+ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+ {
+- struct ftrace_event_call *call = filp->private_data;
++ struct ftrace_event_call *call;
+ struct trace_seq *s;
+- int r;
++ int r = -ENODEV;
+
+ if (*ppos)
+ return 0;
+
+ s = kmalloc(sizeof(*s), GFP_KERNEL);
++
+ if (!s)
+ return -ENOMEM;
+
+ trace_seq_init(s);
+
+- print_event_filter(call, s);
+- r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
++ mutex_lock(&event_mutex);
++ call = event_file_data(filp);
++ if (call)
++ print_event_filter(call, s);
++ mutex_unlock(&event_mutex);
++
++ if (call)
++ r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+
+ kfree(s);
+
+@@ -1027,9 +1034,9 @@ static ssize_t
+ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+ {
+- struct ftrace_event_call *call = filp->private_data;
++ struct ftrace_event_call *call;
+ char *buf;
+- int err;
++ int err = -ENODEV;
+
+ if (cnt >= PAGE_SIZE)
+ return -EINVAL;
+@@ -1044,7 +1051,12 @@ event_filter_write(struct file *filp, co
+ }
+ buf[cnt] = '\0';
+
+- err = apply_event_filter(call, buf);
++ mutex_lock(&event_mutex);
++ call = event_file_data(filp);
++ if (call)
++ err = apply_event_filter(call, buf);
++ mutex_unlock(&event_mutex);
++
+ free_page((unsigned long) buf);
+ if (err < 0)
+ return err;
+--- a/kernel/trace/trace_events_filter.c
++++ b/kernel/trace/trace_events_filter.c
+@@ -631,17 +631,15 @@ static void append_filter_err(struct fil
+ free_page((unsigned long) buf);
+ }
+
++/* caller must hold event_mutex */
+ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
+ {
+- struct event_filter *filter;
++ struct event_filter *filter = call->filter;
+
+- mutex_lock(&event_mutex);
+- filter = call->filter;
+ if (filter && filter->filter_string)
+ trace_seq_printf(s, "%s\n", filter->filter_string);
+ else
+ trace_seq_printf(s, "none\n");
+- mutex_unlock(&event_mutex);
+ }
+
+ void print_subsystem_event_filter(struct event_subsystem *system,
+@@ -1835,23 +1833,22 @@ static int create_system_filter(struct e
+ return err;
+ }
+
++/* caller must hold event_mutex */
+ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
+ {
+ struct event_filter *filter;
+- int err = 0;
+-
+- mutex_lock(&event_mutex);
++ int err;
+
+ if (!strcmp(strstrip(filter_string), "0")) {
+ filter_disable(call);
+ filter = call->filter;
+ if (!filter)
+- goto out_unlock;
++ return 0;
+ RCU_INIT_POINTER(call->filter, NULL);
+ /* Make sure the filter is not being used */
+ synchronize_sched();
+ __free_filter(filter);
+- goto out_unlock;
++ return 0;
+ }
+
+ err = create_filter(call, filter_string, true, &filter);
+@@ -1878,8 +1875,6 @@ int apply_event_filter(struct ftrace_eve
+ __free_filter(tmp);
+ }
+ }
+-out_unlock:
+- mutex_unlock(&event_mutex);
+
+ return err;
+ }
--- /dev/null
+From c5a44a1200c6eda2202434f25325e8ad19533fca Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Fri, 26 Jul 2013 19:25:43 +0200
+Subject: tracing: Change f_start() to take event_mutex and verify i_private != NULL
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit c5a44a1200c6eda2202434f25325e8ad19533fca upstream.
+
+trace_format_open() and trace_format_seq_ops are racy, nothing
+protects ftrace_event_call from trace_remove_event_call().
+
+Change f_start() to take event_mutex and verify i_private != NULL,
+change f_stop() to drop this lock.
+
+This fixes nothing, but now we can change debugfs_remove("format")
+callers to nullify ->i_private and fix the the problem.
+
+Note: the usage of event_mutex is sub-optimal but simple, we can
+change this later.
+
+Link: http://lkml.kernel.org/r/20130726172543.GA3622@redhat.com
+
+Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.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>
+
+
+---
+ kernel/trace/trace_events.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -838,7 +838,7 @@ enum {
+
+ static void *f_next(struct seq_file *m, void *v, loff_t *pos)
+ {
+- struct ftrace_event_call *call = m->private;
++ struct ftrace_event_call *call = event_file_data(m->private);
+ struct ftrace_event_field *field;
+ struct list_head *common_head = &ftrace_common_fields;
+ struct list_head *head = trace_get_fields(call);
+@@ -882,6 +882,11 @@ static void *f_start(struct seq_file *m,
+ loff_t l = 0;
+ void *p;
+
++ /* ->stop() is called even if ->start() fails */
++ mutex_lock(&event_mutex);
++ if (!event_file_data(m->private))
++ return ERR_PTR(-ENODEV);
++
+ /* Start by showing the header */
+ if (!*pos)
+ return (void *)FORMAT_HEADER;
+@@ -896,7 +901,7 @@ static void *f_start(struct seq_file *m,
+
+ static int f_show(struct seq_file *m, void *v)
+ {
+- struct ftrace_event_call *call = m->private;
++ struct ftrace_event_call *call = event_file_data(m->private);
+ struct ftrace_event_field *field;
+ const char *array_descriptor;
+
+@@ -947,6 +952,7 @@ static int f_show(struct seq_file *m, vo
+
+ static void f_stop(struct seq_file *m, void *p)
+ {
++ mutex_unlock(&event_mutex);
+ }
+
+ static const struct seq_operations trace_format_seq_ops = {
+@@ -958,7 +964,6 @@ static const struct seq_operations trace
+
+ static int trace_format_open(struct inode *inode, struct file *file)
+ {
+- struct ftrace_event_call *call = inode->i_private;
+ struct seq_file *m;
+ int ret;
+
+@@ -967,7 +972,7 @@ static int trace_format_open(struct inod
+ return ret;
+
+ m = file->private_data;
+- m->private = call;
++ m->private = file;
+
+ return 0;
+ }
--- /dev/null
+From f6a84bdc75b5c11621dec58db73fe102cbaf40cc Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Fri, 26 Jul 2013 19:25:47 +0200
+Subject: tracing: Introduce remove_event_file_dir()
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit f6a84bdc75b5c11621dec58db73fe102cbaf40cc upstream.
+
+Preparation for the next patch. Extract the common code from
+remove_event_from_tracers() and __trace_remove_event_dirs()
+into the new helper, remove_event_file_dir().
+
+The patch looks more complicated than it actually is, it also
+moves remove_subsystem() up to avoid the forward declaration.
+
+Link: http://lkml.kernel.org/r/20130726172547.GA3629@redhat.com
+
+Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.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>
+
+---
+ kernel/trace/trace_events.c | 47 +++++++++++++++++++++-----------------------
+ 1 file changed, 23 insertions(+), 24 deletions(-)
+
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -407,11 +407,31 @@ static void put_system(struct ftrace_sub
+ mutex_unlock(&event_mutex);
+ }
+
++static void remove_subsystem(struct ftrace_subsystem_dir *dir)
++{
++ if (!dir)
++ return;
++
++ if (!--dir->nr_events) {
++ debugfs_remove_recursive(dir->entry);
++ list_del(&dir->list);
++ __put_system_dir(dir);
++ }
++}
++
+ static void *event_file_data(struct file *filp)
+ {
+ return ACCESS_ONCE(file_inode(filp)->i_private);
+ }
+
++static void remove_event_file_dir(struct ftrace_event_file *file)
++{
++ list_del(&file->list);
++ debugfs_remove_recursive(file->dir);
++ remove_subsystem(file->system);
++ kmem_cache_free(file_cachep, file);
++}
++
+ /*
+ * Open and update trace_array ref count.
+ * Must have the current trace_array passed to it.
+@@ -1571,33 +1591,16 @@ event_create_dir(struct dentry *parent,
+ return 0;
+ }
+
+-static void remove_subsystem(struct ftrace_subsystem_dir *dir)
+-{
+- if (!dir)
+- return;
+-
+- if (!--dir->nr_events) {
+- debugfs_remove_recursive(dir->entry);
+- list_del(&dir->list);
+- __put_system_dir(dir);
+- }
+-}
+-
+ static void remove_event_from_tracers(struct ftrace_event_call *call)
+ {
+ struct ftrace_event_file *file;
+ struct trace_array *tr;
+
+ do_for_each_event_file_safe(tr, file) {
+-
+ if (file->event_call != call)
+ continue;
+
+- list_del(&file->list);
+- debugfs_remove_recursive(file->dir);
+- remove_subsystem(file->system);
+- kmem_cache_free(file_cachep, file);
+-
++ remove_event_file_dir(file);
+ /*
+ * The do_for_each_event_file_safe() is
+ * a double loop. After finding the call for this
+@@ -2330,12 +2333,8 @@ __trace_remove_event_dirs(struct trace_a
+ {
+ struct ftrace_event_file *file, *next;
+
+- list_for_each_entry_safe(file, next, &tr->events, list) {
+- list_del(&file->list);
+- debugfs_remove_recursive(file->dir);
+- remove_subsystem(file->system);
+- kmem_cache_free(file_cachep, file);
+- }
++ list_for_each_entry_safe(file, next, &tr->events, list)
++ remove_event_file_dir(file);
+ }
+
+ static void