mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
perf session: Bounds-check one_mmap event pointer in peek_event
perf_session__peek_event() computes an event pointer directly from file_offset when one_mmap is active, without verifying that file_offset and the subsequent event->header.size fall within the mapped region. A corrupted perf.data file could cause out-of-bounds memory reads. Add one_mmap_size to the session struct and validate both the header and full event fit within the mmap before dereferencing. Reported-by: sashiko-bot@kernel.org # Running on a local machine Reviewed-by: Ian Rogers <irogers@google.com> Cc: Namhyung Kim <namhyung@kernel.org> Assisted-by: Claude:claude-opus-4.6-1m Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
da27c4379c
commit
1e389b7639
|
|
@ -1887,12 +1887,27 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
|
|||
*event_ptr = NULL;
|
||||
|
||||
if (session->one_mmap && !session->header.needs_swap) {
|
||||
event = file_offset - session->one_mmap_offset +
|
||||
session->one_mmap_addr;
|
||||
u64 offset_in_mmap;
|
||||
|
||||
/* Validate offset with integer arithmetic to avoid pointer UB */
|
||||
if ((u64)file_offset < session->one_mmap_offset)
|
||||
return -1;
|
||||
|
||||
offset_in_mmap = (u64)file_offset - session->one_mmap_offset;
|
||||
|
||||
/* Use subtraction to avoid addition overflow */
|
||||
if (offset_in_mmap >= session->one_mmap_size ||
|
||||
session->one_mmap_size - offset_in_mmap < sizeof(struct perf_event_header))
|
||||
return -1;
|
||||
|
||||
event = session->one_mmap_addr + offset_in_mmap;
|
||||
|
||||
/* Every event must at least contain its own header */
|
||||
if (event->header.size < sizeof(struct perf_event_header))
|
||||
return -1;
|
||||
|
||||
/* Ensure full event is within the mmap region */
|
||||
if (session->one_mmap_size - offset_in_mmap < event->header.size)
|
||||
return -1;
|
||||
} else {
|
||||
if (perf_data__is_pipe(session->data))
|
||||
return -1;
|
||||
|
|
@ -2560,6 +2575,14 @@ reader__mmap(struct reader *rd, struct perf_session *session)
|
|||
if (session->one_mmap) {
|
||||
session->one_mmap_addr = buf;
|
||||
session->one_mmap_offset = rd->file_offset;
|
||||
/*
|
||||
* mmap_size was set to the full file extent (data_offset +
|
||||
* data_size) but file_offset was shifted forward by
|
||||
* page_offset for page alignment. Reduce by page_offset
|
||||
* so the bounds check reflects the file-backed portion
|
||||
* of the mapping — pages beyond the file cause SIGBUS.
|
||||
*/
|
||||
session->one_mmap_size = rd->mmap_size - page_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ struct perf_session {
|
|||
void *one_mmap_addr;
|
||||
/** @one_mmap_offset: File offset in perf.data file when mapped. */
|
||||
u64 one_mmap_offset;
|
||||
/** @one_mmap_size: Size of the single mmap in bytes. */
|
||||
u64 one_mmap_size;
|
||||
/** @ordered_events: Used to turn unordered events into ordered ones. */
|
||||
struct ordered_events ordered_events;
|
||||
/** @data: Optional perf data file being read from. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user