]>
Commit | Line | Data |
---|---|---|
5bdb2afd GKH |
1 | From af91568e762d04931dcbdd6bef4655433d8b9418 Mon Sep 17 00:00:00 2001 |
2 | From: Jiri Olsa <jolsa@kernel.org> | |
3 | Date: Wed, 10 Dec 2014 21:23:50 +0100 | |
4 | Subject: perf/x86/intel/uncore: Make sure only uncore events are collected | |
5 | ||
6 | From: Jiri Olsa <jolsa@kernel.org> | |
7 | ||
8 | commit af91568e762d04931dcbdd6bef4655433d8b9418 upstream. | |
9 | ||
10 | The uncore_collect_events functions assumes that event group | |
11 | might contain only uncore events which is wrong, because it | |
12 | might contain any type of events. | |
13 | ||
14 | This bug leads to uncore framework touching 'not' uncore events, | |
15 | which could end up all sorts of bugs. | |
16 | ||
17 | One was triggered by Vince's perf fuzzer, when the uncore code | |
18 | touched breakpoint event private event space as if it was uncore | |
19 | event and caused BUG: | |
20 | ||
21 | BUG: unable to handle kernel paging request at ffffffff82822068 | |
22 | IP: [<ffffffff81020338>] uncore_assign_events+0x188/0x250 | |
23 | ... | |
24 | ||
25 | The code in uncore_assign_events() function was looking for | |
26 | event->hw.idx data while the event was initialized as a | |
27 | breakpoint with different members in event->hw union. | |
28 | ||
29 | This patch forces uncore_collect_events() to collect only uncore | |
30 | events. | |
31 | ||
32 | Reported-by: Vince Weaver <vince@deater.net> | |
33 | Signed-off-by: Jiri Olsa <jolsa@redhat.com> | |
34 | Cc: Arnaldo Carvalho de Melo <acme@redhat.com> | |
35 | Cc: Frederic Weisbecker <fweisbec@gmail.com> | |
36 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
37 | Cc: Peter Zijlstra <peterz@infradead.org> | |
38 | Cc: Stephane Eranian <eranian@google.com> | |
39 | Cc: Yan, Zheng <zheng.z.yan@intel.com> | |
40 | Link: http://lkml.kernel.org/r/1418243031-20367-2-git-send-email-jolsa@kernel.org | |
41 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
42 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
43 | ||
44 | --- | |
45 | arch/x86/kernel/cpu/perf_event_intel_uncore.c | 22 +++++++++++++++++++--- | |
46 | 1 file changed, 19 insertions(+), 3 deletions(-) | |
47 | ||
48 | --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c | |
49 | +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c | |
50 | @@ -276,6 +276,17 @@ static struct intel_uncore_box *uncore_a | |
51 | return box; | |
52 | } | |
53 | ||
54 | +/* | |
55 | + * Using uncore_pmu_event_init pmu event_init callback | |
56 | + * as a detection point for uncore events. | |
57 | + */ | |
58 | +static int uncore_pmu_event_init(struct perf_event *event); | |
59 | + | |
60 | +static bool is_uncore_event(struct perf_event *event) | |
61 | +{ | |
62 | + return event->pmu->event_init == uncore_pmu_event_init; | |
63 | +} | |
64 | + | |
65 | static int | |
66 | uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, bool dogrp) | |
67 | { | |
68 | @@ -290,13 +301,18 @@ uncore_collect_events(struct intel_uncor | |
69 | return -EINVAL; | |
70 | ||
71 | n = box->n_events; | |
72 | - box->event_list[n] = leader; | |
73 | - n++; | |
74 | + | |
75 | + if (is_uncore_event(leader)) { | |
76 | + box->event_list[n] = leader; | |
77 | + n++; | |
78 | + } | |
79 | + | |
80 | if (!dogrp) | |
81 | return n; | |
82 | ||
83 | list_for_each_entry(event, &leader->sibling_list, group_entry) { | |
84 | - if (event->state <= PERF_EVENT_STATE_OFF) | |
85 | + if (!is_uncore_event(event) || | |
86 | + event->state <= PERF_EVENT_STATE_OFF) | |
87 | continue; | |
88 | ||
89 | if (n >= max_count) |