diff options
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/ftrace.c | 13 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 2 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_eprobe.c | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 4 | ||||
| -rw-r--r-- | kernel/trace/trace_events_hist.c | 2 | ||||
| -rw-r--r-- | kernel/trace/trace_events_trigger.c | 22 | ||||
| -rw-r--r-- | kernel/trace/trace_mmiotrace.c | 4 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.c | 13 | ||||
| -rw-r--r-- | kernel/trace/trace_remote.c | 16 | ||||
| -rw-r--r-- | kernel/trace/trace_syscalls.c | 5 |
11 files changed, 67 insertions, 18 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f93e34dd2328..6c47a94f5924 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1098,6 +1098,12 @@ struct ftrace_ops global_ops = { }; /* + * parser_lock - Protects trace_parser state against concurrent operations. + * Held across trace_get_user() and subsequent buffer parsing to prevent races. + */ +static DEFINE_MUTEX(parser_lock); + +/* * Used by the stack unwinder to know about dynamic ftrace trampolines. */ struct ftrace_ops *ftrace_ops_trampoline(unsigned long addr) @@ -5842,6 +5848,8 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, /* iter->hash is a local copy, so we don't need regex_lock */ parser = &iter->parser; + + guard(mutex)(&parser_lock); read = trace_get_user(parser, ubuf, cnt, ppos); if (read >= 0 && trace_parser_loaded(parser) && @@ -6984,12 +6992,14 @@ int ftrace_regex_release(struct inode *inode, struct file *file) iter = file->private_data; parser = &iter->parser; + mutex_lock(&parser_lock); if (trace_parser_loaded(parser)) { int enable = !(iter->flags & FTRACE_ITER_NOTRACE); ftrace_process_regex(iter, parser->buffer, parser->idx, enable); } + mutex_unlock(&parser_lock); trace_parser_put(parser); @@ -7321,10 +7331,12 @@ ftrace_graph_release(struct inode *inode, struct file *file) parser = &fgd->parser; + mutex_lock(&parser_lock); if (trace_parser_loaded((parser))) { ret = ftrace_graph_set_hash(fgd->new_hash, parser->buffer); } + mutex_unlock(&parser_lock); trace_parser_put(parser); @@ -7437,6 +7449,7 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, parser = &fgd->parser; + guard(mutex)(&parser_lock); read = trace_get_user(parser, ubuf, cnt, ppos); if (read >= 0 && trace_parser_loaded(parser) && diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 18710c190c92..01a5e87af299 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6187,7 +6187,7 @@ char *trace_user_fault_read(struct trace_user_buf_info *tinfo, { int cpu = smp_processor_id(); char *buffer = per_cpu_ptr(tinfo->tbuf, cpu)->buf; - unsigned int cnt; + unsigned long long cnt; int trys = 0; int ret; diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 80fe152af1dd..bf77331f56a4 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -1941,6 +1941,7 @@ struct event_trigger_data { struct list_head named_list; struct event_trigger_data *named_data; struct llist_node llist; + void (*private_data_free)(struct event_trigger_data *data); }; /* Avoid typos */ diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c index 50518b071414..bcd97cb24ac9 100644 --- a/kernel/trace/trace_eprobe.c +++ b/kernel/trace/trace_eprobe.c @@ -172,7 +172,8 @@ static bool eprobe_dyn_event_match(const char *system, const char *event, if (!slash) return false; - if (strncmp(ep->event_system, argv[0], slash - argv[0])) + if (strncmp(ep->event_system, argv[0], slash - argv[0]) || + ep->event_system[slash - argv[0]] != '\0') return false; if (strcmp(ep->event_name, slash + 1)) return false; diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index c46e623e7e0d..956692856fa8 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1350,7 +1350,9 @@ __ftrace_set_clr_event_nolock(struct trace_array *tr, const char *match, call = file->event_call; /* If a module is specified, skip events that are not that module */ - if (module && (!call->module || strcmp(module_name(call->module), module))) + if (module && + ((call->flags & TRACE_EVENT_FL_DYNAMIC) || + !call->module || strcmp(module_name(call->module), module))) continue; name = trace_event_name(call); diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 82ce492ab268..58d28cd1afa3 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -6349,6 +6349,7 @@ static void event_hist_trigger_free(struct event_trigger_data *data) trigger_data_free(data); + tracepoint_synchronize_unregister(); remove_hist_vars(hist_data); unregister_field_var_hists(hist_data); @@ -6388,6 +6389,7 @@ static void event_hist_trigger_named_free(struct event_trigger_data *data) del_named_trigger(data); trigger_data_free(data); + tracepoint_synchronize_unregister(); kfree(cmd_ops); } } diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index 655db2e82513..ad83419cb420 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -38,6 +38,13 @@ static void trigger_create_kthread_locked(void) } } +static void trigger_data_free_one(struct event_trigger_data *data) +{ + if (data->private_data_free) + data->private_data_free(data); + kfree(data); +} + static void trigger_data_free_queued_locked(void) { struct event_trigger_data *data, *tmp; @@ -52,7 +59,7 @@ static void trigger_data_free_queued_locked(void) tracepoint_synchronize_unregister(); llist_for_each_entry_safe(data, tmp, llnodes, llist) - kfree(data); + trigger_data_free_one(data); } /* Bulk garbage collection of event_trigger_data elements */ @@ -75,7 +82,7 @@ static int trigger_kthread_fn(void *ignore) tracepoint_synchronize_unregister(); llist_for_each_entry_safe(data, tmp, llnodes, llist) - kfree(data); + trigger_data_free_one(data); } return 0; @@ -1717,6 +1724,14 @@ int event_enable_trigger_print(struct seq_file *m, return 0; } +static void enable_trigger_private_data_free(struct event_trigger_data *data) +{ + struct enable_trigger_data *enable_data = data->private_data; + + trace_event_put_ref(enable_data->file->event_call); + kfree(enable_data); +} + void event_enable_trigger_free(struct event_trigger_data *data) { struct enable_trigger_data *enable_data = data->private_data; @@ -1728,9 +1743,8 @@ void event_enable_trigger_free(struct event_trigger_data *data) if (!data->ref) { /* Remove the SOFT_MODE flag */ trace_event_enable_disable(enable_data->file, 0, 1); - trace_event_put_ref(enable_data->file->event_call); + data->private_data_free = enable_trigger_private_data_free; trigger_data_free(data); - kfree(enable_data); } } diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c index 226cf66e0d68..b88b8d9923ad 100644 --- a/kernel/trace/trace_mmiotrace.c +++ b/kernel/trace/trace_mmiotrace.c @@ -109,7 +109,6 @@ static void mmio_pipe_open(struct trace_iterator *iter) iter->private = hiter; } -/* XXX: This is not called when the pipe is closed! */ static void mmio_close(struct trace_iterator *iter) { struct header_iter *hiter = iter->private; @@ -146,7 +145,7 @@ static ssize_t mmio_read(struct trace_iterator *iter, struct file *filp, goto print_out; } - if (!hiter) + if (!hiter || !hiter->dev) return 0; mmio_print_pcidev(s, hiter->dev); @@ -279,6 +278,7 @@ static struct tracer mmio_tracer __read_mostly = .start = mmio_trace_start, .pipe_open = mmio_pipe_open, .close = mmio_close, + .pipe_close = mmio_close, .read = mmio_read, .print_line = mmio_print_line, .noboot = true, diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index d17cfee77d9c..506e6037e163 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -188,7 +188,7 @@ void __trace_probe_log_err(int offset, int err_type) lockdep_assert_held(&dyn_event_ops_mutex); - if (!trace_probe_log.argv) + if (!trace_probe_log.argv || !trace_probe_log.argc) return; /* Recalculate the length and allocate buffer */ @@ -2013,7 +2013,7 @@ int traceprobe_update_arg(struct probe_arg *arg) } /* When len=0, we just calculate the needed length */ -#define LEN_OR_ZERO (len ? len - pos : 0) +#define LEN_OR_ZERO (len > pos ? len - pos : 0) static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, enum probe_print_type ptype) { @@ -2338,16 +2338,17 @@ int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b) bool trace_probe_match_command_args(struct trace_probe *tp, int argc, const char **argv) { - char buf[MAX_ARGSTR_LEN + 1]; int i; if (tp->nr_args < argc) return false; for (i = 0; i < argc; i++) { - snprintf(buf, sizeof(buf), "%s=%s", - tp->args[i].name, tp->args[i].comm); - if (strcmp(buf, argv[i])) + int len = strlen(tp->args[i].name); + + if (strncmp(argv[i], tp->args[i].name, len) || + argv[i][len] != '=' || + strcmp(argv[i] + len + 1, tp->args[i].comm)) return false; } return true; diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c index 0f6ef5c36d84..e6724f947170 100644 --- a/kernel/trace/trace_remote.c +++ b/kernel/trace/trace_remote.c @@ -1004,11 +1004,10 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, desc->nr_cpus++; for (id = 0; id < nr_pages; id++) { + rb_desc->nr_page_va++; rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL); if (!rb_desc->page_va[id]) goto err; - - rb_desc->nr_page_va++; } rb_desc = __next_ring_buffer_desc(rb_desc); } @@ -1150,10 +1149,21 @@ static ssize_t remote_events_dir_enable_write(struct file *filp, const char __us for (i = 0; i < remote->nr_events; i++) { struct remote_event *evt = &remote->events[i]; + int eret; - trace_remote_enable_event(remote, evt, enable); + eret = trace_remote_enable_event(remote, evt, enable); + /* + * Save the first error and return that. Some events + * may still have been enabled, but let the user + * know that something went wrong. + */ + if (!ret && eret) + ret = eret; } + if (ret) + return ret; + return count; } diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index e98ee7e1e66f..8a4f3c75e39f 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -1451,6 +1451,11 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) if (syscall_get_data(sys_data, args, &user_ptr, &size, user_sizes, &uargs, buf_size) < 0) return; + + /* The above may have caused a migration */ + head = this_cpu_ptr(sys_data->enter_event->perf_events); + if (hlist_empty(head)) + return; } /* get the size after alignment with the u32 buffer size field */ |
