perf trace-event: Fix heap overflows in read_ftrace_printk()/read_saved_cmdline()

Both functions read an attacker-controlled size directly from the
input file and pass size + 1 to malloc() before reading size bytes
into the result:

read_ftrace_printk(): size is an unsigned int from read4(). When
size == UINT_MAX, size + 1 overflows to 0, so malloc(0) returns a
minimal allocation while size itself remains UINT_MAX.

read_saved_cmdline(): size is an unsigned long long from read8().
When size == ULLONG_MAX, size + 1 overflows to 0 the same way.

In both cases, do_read(buf, size) then attempts to read the full,
unwrapped size into the tiny allocated buffer, a heap buffer
overflow.

This was previously masked by do_read()'s size parameter being
'int': passing these values truncated them, which the read()
syscall's own boundary checks rejected before any data was read.
Fixing that truncation (widening do_read() to size_t) is correct
on its own, but it removes this accidental protection and exposes
the pre-existing missing bounds check in both functions.

Reject the one value that causes the overflow before it's used, in
each function.

Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Tanushree Shah 2026-07-26 00:19:52 +05:30 committed by Namhyung Kim
parent 6c07d49ef3
commit c291f143cc

View File

@ -15,6 +15,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include "trace-event.h"
#include "debug.h"
@ -180,6 +181,11 @@ static int read_ftrace_printk(struct tep_handle *pevent)
if (!size)
return 0;
if (size == UINT_MAX) {
pr_debug("invalid ftrace printk size\n");
return -1;
}
buf = malloc(size + 1);
if (buf == NULL)
return -1;
@ -357,6 +363,11 @@ static int read_saved_cmdline(struct tep_handle *pevent)
if (!size)
return 0;
if (size == ULLONG_MAX) {
pr_debug("invalid saved cmdline size");
return -1;
}
buf = malloc(size + 1);
if (buf == NULL) {
pr_debug("memory allocation failure\n");