aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-06-18 02:00:17 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-18 02:15:47 -0400
commit7522060c95395f479ee4a6af3bbf9e097e92e48f (patch)
tree3530611cfd45c75c5a1952210edb2953598a9afe
parentb25bcf2f133b1e6216c3d40be394756107d3880f (diff)
perf report: Add validation of call-chain entries
Add boundary checks for call-chain events. In case of corrupted entries we could crash otherwise. Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--include/linux/perf_counter.h20
-rw-r--r--tools/perf/builtin-report.c74
2 files changed, 56 insertions, 38 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index eccae437fe37..a7d3a61a59b7 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -337,6 +337,16 @@ enum perf_event_type {
337 */ 337 */
338}; 338};
339 339
340#define MAX_STACK_DEPTH 255
341
342struct perf_callchain_entry {
343 __u16 nr;
344 __u16 hv;
345 __u16 kernel;
346 __u16 user;
347 __u64 ip[MAX_STACK_DEPTH];
348};
349
340#ifdef __KERNEL__ 350#ifdef __KERNEL__
341/* 351/*
342 * Kernel-internal data types and definitions: 352 * Kernel-internal data types and definitions:
@@ -652,16 +662,6 @@ extern void perf_counter_fork(struct task_struct *tsk);
652 662
653extern void perf_counter_task_migration(struct task_struct *task, int cpu); 663extern void perf_counter_task_migration(struct task_struct *task, int cpu);
654 664
655#define MAX_STACK_DEPTH 255
656
657struct perf_callchain_entry {
658 u16 nr;
659 u16 hv;
660 u16 kernel;
661 u16 user;
662 u64 ip[MAX_STACK_DEPTH];
663};
664
665extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs); 665extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
666 666
667extern int sysctl_perf_counter_paranoid; 667extern int sysctl_perf_counter_paranoid;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 986834623b43..e14e98676171 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -39,6 +39,8 @@ static int dump_trace = 0;
39#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) 39#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
40 40
41static int verbose; 41static int verbose;
42#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
43
42static int full_paths; 44static int full_paths;
43 45
44static unsigned long page_size; 46static unsigned long page_size;
@@ -47,14 +49,6 @@ static unsigned long mmap_window = 32;
47static char *parent_pattern = "^sys_|^do_page_fault"; 49static char *parent_pattern = "^sys_|^do_page_fault";
48static regex_t parent_regex; 50static regex_t parent_regex;
49 51
50struct ip_chain_event {
51 __u16 nr;
52 __u16 hv;
53 __u16 kernel;
54 __u16 user;
55 __u64 ips[];
56};
57
58struct ip_event { 52struct ip_event {
59 struct perf_event_header header; 53 struct perf_event_header header;
60 __u64 ip; 54 __u64 ip;
@@ -131,15 +125,11 @@ static struct dso *dsos__findnew(const char *name)
131 125
132 nr = dso__load(dso, NULL, verbose); 126 nr = dso__load(dso, NULL, verbose);
133 if (nr < 0) { 127 if (nr < 0) {
134 if (verbose) 128 eprintf("Failed to open: %s\n", name);
135 fprintf(stderr, "Failed to open: %s\n", name);
136 goto out_delete_dso; 129 goto out_delete_dso;
137 } 130 }
138 if (!nr && verbose) { 131 if (!nr)
139 fprintf(stderr, 132 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
140 "No symbols found in: %s, maybe install a debug package?\n",
141 name);
142 }
143 133
144 dsos__add(dso); 134 dsos__add(dso);
145 135
@@ -844,7 +834,7 @@ static struct symbol *call__match(struct symbol *sym)
844 834
845static int 835static int
846hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 836hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
847 struct symbol *sym, __u64 ip, struct ip_chain_event *chain, 837 struct symbol *sym, __u64 ip, struct perf_callchain_entry *chain,
848 char level, __u64 count) 838 char level, __u64 count)
849{ 839{
850 struct rb_node **p = &hist.rb_node; 840 struct rb_node **p = &hist.rb_node;
@@ -868,7 +858,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
868 __u64 ip; 858 __u64 ip;
869 859
870 for (i = 0; i < chain->kernel; i++) { 860 for (i = 0; i < chain->kernel; i++) {
871 ip = chain->ips[nr + i]; 861 ip = chain->ip[nr + i];
872 dso = kernel_dso; 862 dso = kernel_dso;
873 sym = resolve_symbol(thread, NULL, &dso, &ip); 863 sym = resolve_symbol(thread, NULL, &dso, &ip);
874 entry.parent = call__match(sym); 864 entry.parent = call__match(sym);
@@ -878,7 +868,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
878 nr += i; 868 nr += i;
879 869
880 for (i = 0; i < chain->user; i++) { 870 for (i = 0; i < chain->user; i++) {
881 ip = chain->ips[nr + i]; 871 ip = chain->ip[nr + i];
882 sym = resolve_symbol(thread, NULL, NULL, &ip); 872 sym = resolve_symbol(thread, NULL, NULL, &ip);
883 entry.parent = call__match(sym); 873 entry.parent = call__match(sym);
884 if (entry.parent) 874 if (entry.parent)
@@ -1080,6 +1070,30 @@ static unsigned long total = 0,
1080 total_fork = 0, 1070 total_fork = 0,
1081 total_unknown = 0; 1071 total_unknown = 0;
1082 1072
1073static int validate_chain(struct perf_callchain_entry *chain, event_t *event)
1074{
1075 unsigned int chain_size;
1076
1077 if (chain->nr > MAX_STACK_DEPTH)
1078 return -1;
1079 if (chain->hv > MAX_STACK_DEPTH)
1080 return -1;
1081 if (chain->kernel > MAX_STACK_DEPTH)
1082 return -1;
1083 if (chain->user > MAX_STACK_DEPTH)
1084 return -1;
1085 if (chain->hv + chain->kernel + chain->user != chain->nr)
1086 return -1;
1087
1088 chain_size = event->header.size;
1089 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1090
1091 if (chain->nr*sizeof(__u64) > chain_size)
1092 return -1;
1093
1094 return 0;
1095}
1096
1083static int 1097static int
1084process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 1098process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1085{ 1099{
@@ -1091,7 +1105,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1091 __u64 period = 1; 1105 __u64 period = 1;
1092 struct map *map = NULL; 1106 struct map *map = NULL;
1093 void *more_data = event->ip.__more_data; 1107 void *more_data = event->ip.__more_data;
1094 struct ip_chain_event *chain = NULL; 1108 struct perf_callchain_entry *chain = NULL;
1095 1109
1096 if (event->header.type & PERF_SAMPLE_PERIOD) { 1110 if (event->header.type & PERF_SAMPLE_PERIOD) {
1097 period = *(__u64 *)more_data; 1111 period = *(__u64 *)more_data;
@@ -1111,21 +1125,26 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1111 1125
1112 chain = (void *)more_data; 1126 chain = (void *)more_data;
1113 1127
1114 if (dump_trace) { 1128 dprintf("... chain: u:%d, k:%d, nr:%d\n",
1115 dprintf("... chain: u:%d, k:%d, nr:%d\n", 1129 chain->user,
1116 chain->user, 1130 chain->kernel,
1117 chain->kernel, 1131 chain->nr);
1118 chain->nr);
1119 1132
1133 if (validate_chain(chain, event) < 0) {
1134 eprintf("call-chain problem with event, skipping it.\n");
1135 return 0;
1136 }
1137
1138 if (dump_trace) {
1120 for (i = 0; i < chain->nr; i++) 1139 for (i = 0; i < chain->nr; i++)
1121 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); 1140 dprintf("..... %2d: %016Lx\n", i, chain->ip[i]);
1122 } 1141 }
1123 } 1142 }
1124 1143
1125 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1144 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1126 1145
1127 if (thread == NULL) { 1146 if (thread == NULL) {
1128 fprintf(stderr, "problem processing %d event, skipping it.\n", 1147 eprintf("problem processing %d event, skipping it.\n",
1129 event->header.type); 1148 event->header.type);
1130 return -1; 1149 return -1;
1131 } 1150 }
@@ -1153,8 +1172,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1153 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 1172 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1154 1173
1155 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 1174 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1156 fprintf(stderr, 1175 eprintf("problem incrementing symbol count, skipping event\n");
1157 "problem incrementing symbol count, skipping event\n");
1158 return -1; 1176 return -1;
1159 } 1177 }
1160 } 1178 }