diff options
Diffstat (limited to 'tools/perf/util/evsel.c')
-rw-r--r-- | tools/perf/util/evsel.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d6fd59beb86..ee0fe0dffa7 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -303,8 +303,20 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type, return 0; } +static bool sample_overlap(const union perf_event *event, + const void *offset, u64 size) +{ + const void *base = event; + + if (offset + size > base + event->header.size) + return true; + + return false; +} + int perf_event__parse_sample(const union perf_event *event, u64 type, - bool sample_id_all, struct perf_sample *data) + int sample_size, bool sample_id_all, + struct perf_sample *data) { const u64 *array; @@ -319,6 +331,9 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, array = event->sample.array; + if (sample_size + sizeof(event->header) > event->header.size) + return -EFAULT; + if (type & PERF_SAMPLE_IP) { data->ip = event->ip.ip; array++; @@ -369,14 +384,29 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, } if (type & PERF_SAMPLE_CALLCHAIN) { + if (sample_overlap(event, array, sizeof(data->callchain->nr))) + return -EFAULT; + data->callchain = (struct ip_callchain *)array; + + if (sample_overlap(event, array, data->callchain->nr)) + return -EFAULT; + array += 1 + data->callchain->nr; } if (type & PERF_SAMPLE_RAW) { u32 *p = (u32 *)array; + + if (sample_overlap(event, array, sizeof(u32))) + return -EFAULT; + data->raw_size = *p; p++; + + if (sample_overlap(event, p, data->raw_size)) + return -EFAULT; + data->raw_data = p; } |