diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2013-07-26 13:25:36 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2013-07-29 22:05:40 -0400 |
| commit | bc6f6b08dee5645770efb4b76186ded313f23752 (patch) | |
| tree | 4f2a94646a39b8454e21bed38f093f73c8752345 /kernel | |
| parent | 1a11126bcb7c93c289bf3218fa546fd3b0c0df8b (diff) | |
tracing: Change event_enable/disable_read() to verify i_private != NULL
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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace_events.c | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index c2d13c528c3c..3dfa8419d0dc 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -684,15 +684,25 @@ static ssize_t | |||
| 684 | event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | 684 | event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, |
| 685 | loff_t *ppos) | 685 | loff_t *ppos) |
| 686 | { | 686 | { |
| 687 | struct ftrace_event_file *file = filp->private_data; | 687 | struct ftrace_event_file *file; |
| 688 | unsigned long flags; | ||
| 688 | char buf[4] = "0"; | 689 | char buf[4] = "0"; |
| 689 | 690 | ||
| 690 | if (file->flags & FTRACE_EVENT_FL_ENABLED && | 691 | mutex_lock(&event_mutex); |
| 691 | !(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)) | 692 | file = event_file_data(filp); |
| 693 | if (likely(file)) | ||
| 694 | flags = file->flags; | ||
| 695 | mutex_unlock(&event_mutex); | ||
| 696 | |||
| 697 | if (!file) | ||
| 698 | return -ENODEV; | ||
| 699 | |||
| 700 | if (flags & FTRACE_EVENT_FL_ENABLED && | ||
| 701 | !(flags & FTRACE_EVENT_FL_SOFT_DISABLED)) | ||
| 692 | strcpy(buf, "1"); | 702 | strcpy(buf, "1"); |
| 693 | 703 | ||
| 694 | if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED || | 704 | if (flags & FTRACE_EVENT_FL_SOFT_DISABLED || |
| 695 | file->flags & FTRACE_EVENT_FL_SOFT_MODE) | 705 | flags & FTRACE_EVENT_FL_SOFT_MODE) |
| 696 | strcat(buf, "*"); | 706 | strcat(buf, "*"); |
| 697 | 707 | ||
| 698 | strcat(buf, "\n"); | 708 | strcat(buf, "\n"); |
| @@ -704,13 +714,10 @@ static ssize_t | |||
| 704 | event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | 714 | event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, |
| 705 | loff_t *ppos) | 715 | loff_t *ppos) |
| 706 | { | 716 | { |
| 707 | struct ftrace_event_file *file = filp->private_data; | 717 | struct ftrace_event_file *file; |
| 708 | unsigned long val; | 718 | unsigned long val; |
| 709 | int ret; | 719 | int ret; |
| 710 | 720 | ||
| 711 | if (!file) | ||
| 712 | return -EINVAL; | ||
| 713 | |||
| 714 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); | 721 | ret = kstrtoul_from_user(ubuf, cnt, 10, &val); |
| 715 | if (ret) | 722 | if (ret) |
| 716 | return ret; | 723 | return ret; |
| @@ -722,8 +729,11 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
| 722 | switch (val) { | 729 | switch (val) { |
| 723 | case 0: | 730 | case 0: |
| 724 | case 1: | 731 | case 1: |
| 732 | ret = -ENODEV; | ||
| 725 | mutex_lock(&event_mutex); | 733 | mutex_lock(&event_mutex); |
| 726 | ret = ftrace_event_enable_disable(file, val); | 734 | file = event_file_data(filp); |
| 735 | if (likely(file)) | ||
| 736 | ret = ftrace_event_enable_disable(file, val); | ||
| 727 | mutex_unlock(&event_mutex); | 737 | mutex_unlock(&event_mutex); |
| 728 | break; | 738 | break; |
| 729 | 739 | ||
