diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-07-26 13:25:36 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-29 12:47:33 -0400 |
commit | df89bf77ca930f69ba07fd459f735ec3cac69f8f (patch) | |
tree | 1558c0cf64c880d8555bc07154b5cdd755fc40a0 /kernel/trace | |
parent | fdb65fe265a389144db73cca023266dd6d5ff8d9 (diff) |
tracing: Change event_enable/disable_read() to verify i_private != NULL
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>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace_events.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index fd16a254173c..e8c445d1f190 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -682,13 +682,23 @@ static ssize_t | |||
682 | event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | 682 | event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, |
683 | loff_t *ppos) | 683 | loff_t *ppos) |
684 | { | 684 | { |
685 | struct ftrace_event_file *file = filp->private_data; | 685 | struct ftrace_event_file *file; |
686 | unsigned long flags; | ||
686 | char *buf; | 687 | char *buf; |
687 | 688 | ||
688 | if (file->flags & FTRACE_EVENT_FL_ENABLED) { | 689 | mutex_lock(&event_mutex); |
689 | if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED) | 690 | file = event_file_data(filp); |
691 | if (likely(file)) | ||
692 | flags = file->flags; | ||
693 | mutex_unlock(&event_mutex); | ||
694 | |||
695 | if (!file) | ||
696 | return -ENODEV; | ||
697 | |||
698 | if (flags & FTRACE_EVENT_FL_ENABLED) { | ||
699 | if (flags & FTRACE_EVENT_FL_SOFT_DISABLED) | ||
690 | buf = "0*\n"; | 700 | buf = "0*\n"; |
691 | else if (file->flags & FTRACE_EVENT_FL_SOFT_MODE) | 701 | else if (flags & FTRACE_EVENT_FL_SOFT_MODE) |
692 | buf = "1*\n"; | 702 | buf = "1*\n"; |
693 | else | 703 | else |
694 | buf = "1\n"; | 704 | buf = "1\n"; |
@@ -702,13 +712,10 @@ static ssize_t | |||
702 | event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | 712 | event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, |
703 | loff_t *ppos) | 713 | loff_t *ppos) |
704 | { | 714 | { |
705 | struct ftrace_event_file *file = filp->private_data; | 715 | struct ftrace_event_file *file; |
706 | unsigned long val; | 716 | unsigned long val; |
707 | int ret; | 717 | int ret; |
708 | 718 | ||
709 | if (!file) | ||
710 | return -EINVAL; | ||
711 | |||
712 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); | 719 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
713 | if (ret) | 720 | if (ret) |
714 | return ret; | 721 | return ret; |
@@ -720,8 +727,11 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
720 | switch (val) { | 727 | switch (val) { |
721 | case 0: | 728 | case 0: |
722 | case 1: | 729 | case 1: |
730 | ret = -ENODEV; | ||
723 | mutex_lock(&event_mutex); | 731 | mutex_lock(&event_mutex); |
724 | ret = ftrace_event_enable_disable(file, val); | 732 | file = event_file_data(filp); |
733 | if (likely(file)) | ||
734 | ret = ftrace_event_enable_disable(file, val); | ||
725 | mutex_unlock(&event_mutex); | 735 | mutex_unlock(&event_mutex); |
726 | break; | 736 | break; |
727 | 737 | ||