| From 7147dc2821c541b15da1f595d3287cf324b33695 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 29 Mar 2022 20:11:30 -0700 |
| Subject: perf session: Remap buf if there is no space for event |
| |
| From: Denis Nikitin <denik@chromium.org> |
| |
| [ Upstream commit bc21e74d4775f883ae1f542c1f1dc7205b15d925 ] |
| |
| If a perf event doesn't fit into remaining buffer space return NULL to |
| remap buf and fetch the event again. |
| |
| Keep the logic to error out on inadequate input from fuzzing. |
| |
| This fixes perf failing on ChromeOS (with 32b userspace): |
| |
| $ perf report -v -i perf.data |
| ... |
| prefetch_event: head=0x1fffff8 event->header_size=0x30, mmap_size=0x2000000: fuzzed or compressed perf.data? |
| Error: |
| failed to process sample |
| |
| Fixes: 57fc032ad643ffd0 ("perf session: Avoid infinite loop when seeing invalid header.size") |
| Reviewed-by: James Clark <james.clark@arm.com> |
| Signed-off-by: Denis Nikitin <denik@chromium.org> |
| Acked-by: Jiri Olsa <jolsa@kernel.org> |
| Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> |
| Cc: Alexey Budankov <alexey.budankov@linux.intel.com> |
| Cc: Namhyung Kim <namhyung@kernel.org> |
| Link: https://lore.kernel.org/r/20220330031130.2152327-1-denik@chromium.org |
| Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| tools/perf/util/session.c | 15 ++++++++++++--- |
| 1 file changed, 12 insertions(+), 3 deletions(-) |
| |
| diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c |
| index d8857d1b6d7c..c64953dabcf5 100644 |
| --- a/tools/perf/util/session.c |
| +++ b/tools/perf/util/session.c |
| @@ -2082,6 +2082,7 @@ prefetch_event(char *buf, u64 head, size_t mmap_size, |
| bool needs_swap, union perf_event *error) |
| { |
| union perf_event *event; |
| + u16 event_size; |
| |
| /* |
| * Ensure we have enough space remaining to read |
| @@ -2094,15 +2095,23 @@ prefetch_event(char *buf, u64 head, size_t mmap_size, |
| if (needs_swap) |
| perf_event_header__bswap(&event->header); |
| |
| - if (head + event->header.size <= mmap_size) |
| + event_size = event->header.size; |
| + if (head + event_size <= mmap_size) |
| return event; |
| |
| /* We're not fetching the event so swap back again */ |
| if (needs_swap) |
| perf_event_header__bswap(&event->header); |
| |
| - pr_debug("%s: head=%#" PRIx64 " event->header_size=%#x, mmap_size=%#zx:" |
| - " fuzzed or compressed perf.data?\n",__func__, head, event->header.size, mmap_size); |
| + /* Check if the event fits into the next mmapped buf. */ |
| + if (event_size <= mmap_size - head % page_size) { |
| + /* Remap buf and fetch again. */ |
| + return NULL; |
| + } |
| + |
| + /* Invalid input. Event size should never exceed mmap_size. */ |
| + pr_debug("%s: head=%#" PRIx64 " event->header.size=%#x, mmap_size=%#zx:" |
| + " fuzzed or compressed perf.data?\n", __func__, head, event_size, mmap_size); |
| |
| return error; |
| } |
| -- |
| 2.35.1 |
| |