tracing/uprobe: Fix to make trace_uprobe_filter alignment safe
[ Upstream commit b61387cb732cf283d318b2165c44913525fe545f ] Commit 99c9a923e97a ("tracing/uprobe: Fix double perf_event linking on multiprobe uprobe") moved trace_uprobe_filter on trace_probe_event. However, since it introduced a flexible data structure with char array and type casting, the alignment of trace_uprobe_filter can be broken. This changes the type of the array to trace_uprobe_filter data strucure to fix it. Link: http://lore.kernel.org/r/20200120124022.GA14897@hirez.programming.kicks-ass.net Link: http://lkml.kernel.org/r/157966340499.5107.10978352478952144902.stgit@devnote2 Fixes: 99c9a923e97a ("tracing/uprobe: Fix double perf_event linking on multiprobe uprobe") Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
5f9b8c5a46
commit
3353852afe
@ -290,7 +290,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
|
|||||||
INIT_HLIST_NODE(&tk->rp.kp.hlist);
|
INIT_HLIST_NODE(&tk->rp.kp.hlist);
|
||||||
INIT_LIST_HEAD(&tk->rp.kp.list);
|
INIT_LIST_HEAD(&tk->rp.kp.list);
|
||||||
|
|
||||||
ret = trace_probe_init(&tk->tp, event, group, 0);
|
ret = trace_probe_init(&tk->tp, event, group, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -984,16 +984,19 @@ void trace_probe_cleanup(struct trace_probe *tp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int trace_probe_init(struct trace_probe *tp, const char *event,
|
int trace_probe_init(struct trace_probe *tp, const char *event,
|
||||||
const char *group, size_t event_data_size)
|
const char *group, bool alloc_filter)
|
||||||
{
|
{
|
||||||
struct trace_event_call *call;
|
struct trace_event_call *call;
|
||||||
|
size_t size = sizeof(struct trace_probe_event);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!event || !group)
|
if (!event || !group)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
tp->event = kzalloc(sizeof(struct trace_probe_event) + event_data_size,
|
if (alloc_filter)
|
||||||
GFP_KERNEL);
|
size += sizeof(struct trace_uprobe_filter);
|
||||||
|
|
||||||
|
tp->event = kzalloc(size, GFP_KERNEL);
|
||||||
if (!tp->event)
|
if (!tp->event)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -223,6 +223,12 @@ struct probe_arg {
|
|||||||
const struct fetch_type *type; /* Type of this argument */
|
const struct fetch_type *type; /* Type of this argument */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct trace_uprobe_filter {
|
||||||
|
rwlock_t rwlock;
|
||||||
|
int nr_systemwide;
|
||||||
|
struct list_head perf_events;
|
||||||
|
};
|
||||||
|
|
||||||
/* Event call and class holder */
|
/* Event call and class holder */
|
||||||
struct trace_probe_event {
|
struct trace_probe_event {
|
||||||
unsigned int flags; /* For TP_FLAG_* */
|
unsigned int flags; /* For TP_FLAG_* */
|
||||||
@ -230,7 +236,7 @@ struct trace_probe_event {
|
|||||||
struct trace_event_call call;
|
struct trace_event_call call;
|
||||||
struct list_head files;
|
struct list_head files;
|
||||||
struct list_head probes;
|
struct list_head probes;
|
||||||
char data[0];
|
struct trace_uprobe_filter filter[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct trace_probe {
|
struct trace_probe {
|
||||||
@ -323,7 +329,7 @@ static inline bool trace_probe_has_single_file(struct trace_probe *tp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int trace_probe_init(struct trace_probe *tp, const char *event,
|
int trace_probe_init(struct trace_probe *tp, const char *event,
|
||||||
const char *group, size_t event_data_size);
|
const char *group, bool alloc_filter);
|
||||||
void trace_probe_cleanup(struct trace_probe *tp);
|
void trace_probe_cleanup(struct trace_probe *tp);
|
||||||
int trace_probe_append(struct trace_probe *tp, struct trace_probe *to);
|
int trace_probe_append(struct trace_probe *tp, struct trace_probe *to);
|
||||||
void trace_probe_unlink(struct trace_probe *tp);
|
void trace_probe_unlink(struct trace_probe *tp);
|
||||||
|
@ -34,12 +34,6 @@ struct uprobe_trace_entry_head {
|
|||||||
#define DATAOF_TRACE_ENTRY(entry, is_return) \
|
#define DATAOF_TRACE_ENTRY(entry, is_return) \
|
||||||
((void*)(entry) + SIZEOF_TRACE_ENTRY(is_return))
|
((void*)(entry) + SIZEOF_TRACE_ENTRY(is_return))
|
||||||
|
|
||||||
struct trace_uprobe_filter {
|
|
||||||
rwlock_t rwlock;
|
|
||||||
int nr_systemwide;
|
|
||||||
struct list_head perf_events;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int trace_uprobe_create(int argc, const char **argv);
|
static int trace_uprobe_create(int argc, const char **argv);
|
||||||
static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev);
|
static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev);
|
||||||
static int trace_uprobe_release(struct dyn_event *ev);
|
static int trace_uprobe_release(struct dyn_event *ev);
|
||||||
@ -263,14 +257,6 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
|
|||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(process_fetch_insn)
|
NOKPROBE_SYMBOL(process_fetch_insn)
|
||||||
|
|
||||||
static struct trace_uprobe_filter *
|
|
||||||
trace_uprobe_get_filter(struct trace_uprobe *tu)
|
|
||||||
{
|
|
||||||
struct trace_probe_event *event = tu->tp.event;
|
|
||||||
|
|
||||||
return (struct trace_uprobe_filter *)&event->data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
|
static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
|
||||||
{
|
{
|
||||||
rwlock_init(&filter->rwlock);
|
rwlock_init(&filter->rwlock);
|
||||||
@ -358,8 +344,7 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
|
|||||||
if (!tu)
|
if (!tu)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
ret = trace_probe_init(&tu->tp, event, group,
|
ret = trace_probe_init(&tu->tp, event, group, true);
|
||||||
sizeof(struct trace_uprobe_filter));
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -367,7 +352,7 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
|
|||||||
tu->consumer.handler = uprobe_dispatcher;
|
tu->consumer.handler = uprobe_dispatcher;
|
||||||
if (is_ret)
|
if (is_ret)
|
||||||
tu->consumer.ret_handler = uretprobe_dispatcher;
|
tu->consumer.ret_handler = uretprobe_dispatcher;
|
||||||
init_trace_uprobe_filter(trace_uprobe_get_filter(tu));
|
init_trace_uprobe_filter(tu->tp.event->filter);
|
||||||
return tu;
|
return tu;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -1076,7 +1061,7 @@ static void __probe_event_disable(struct trace_probe *tp)
|
|||||||
struct trace_uprobe *tu;
|
struct trace_uprobe *tu;
|
||||||
|
|
||||||
tu = container_of(tp, struct trace_uprobe, tp);
|
tu = container_of(tp, struct trace_uprobe, tp);
|
||||||
WARN_ON(!uprobe_filter_is_empty(trace_uprobe_get_filter(tu)));
|
WARN_ON(!uprobe_filter_is_empty(tu->tp.event->filter));
|
||||||
|
|
||||||
list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
|
list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
|
||||||
tu = container_of(pos, struct trace_uprobe, tp);
|
tu = container_of(pos, struct trace_uprobe, tp);
|
||||||
@ -1117,7 +1102,7 @@ static int probe_event_enable(struct trace_event_call *call,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tu = container_of(tp, struct trace_uprobe, tp);
|
tu = container_of(tp, struct trace_uprobe, tp);
|
||||||
WARN_ON(!uprobe_filter_is_empty(trace_uprobe_get_filter(tu)));
|
WARN_ON(!uprobe_filter_is_empty(tu->tp.event->filter));
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1281,7 +1266,7 @@ static int uprobe_perf_close(struct trace_event_call *call,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
tu = container_of(tp, struct trace_uprobe, tp);
|
tu = container_of(tp, struct trace_uprobe, tp);
|
||||||
if (trace_uprobe_filter_remove(trace_uprobe_get_filter(tu), event))
|
if (trace_uprobe_filter_remove(tu->tp.event->filter, event))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
|
list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
|
||||||
@ -1306,7 +1291,7 @@ static int uprobe_perf_open(struct trace_event_call *call,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
tu = container_of(tp, struct trace_uprobe, tp);
|
tu = container_of(tp, struct trace_uprobe, tp);
|
||||||
if (trace_uprobe_filter_add(trace_uprobe_get_filter(tu), event))
|
if (trace_uprobe_filter_add(tu->tp.event->filter, event))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
|
list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
|
||||||
@ -1328,7 +1313,7 @@ static bool uprobe_perf_filter(struct uprobe_consumer *uc,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
tu = container_of(uc, struct trace_uprobe, consumer);
|
tu = container_of(uc, struct trace_uprobe, consumer);
|
||||||
filter = trace_uprobe_get_filter(tu);
|
filter = tu->tp.event->filter;
|
||||||
|
|
||||||
read_lock(&filter->rwlock);
|
read_lock(&filter->rwlock);
|
||||||
ret = __uprobe_perf_filter(filter, mm);
|
ret = __uprobe_perf_filter(filter, mm);
|
||||||
|
Loading…
Reference in New Issue
Block a user