]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf header: Sanity check HEADER_BPF_PROG_INFO
authorArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 10 Apr 2026 22:09:04 +0000 (19:09 -0300)
committerNamhyung Kim <namhyung@kernel.org>
Tue, 14 Apr 2026 06:21:53 +0000 (23:21 -0700)
Add validation to process_bpf_prog_info() to harden against malformed
perf.data files:

- Upper bound on BPF program count (max 131072)
- Upper bound on per-program data_len (max 256MB)

Cc: Ian Rogers <irogers@google.com>
Assisted-by: Claude Code:claude-opus-4-6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/header.c

index 37c1afbc081672f1f8f6b9f8eec29d014c7e7885..705f1ab44bc934861669b52c6e74860a41b4c4fd 100644 (file)
@@ -63,6 +63,8 @@
 #include <event-parse.h>
 #endif
 
+#define MAX_BPF_DATA_LEN       (256 * 1024 * 1024)
+#define MAX_BPF_PROGS          131072
 #define MAX_CACHE_ENTRIES      32768
 #define MAX_GROUP_DESC         32768
 #define MAX_NUMA_NODES         4096
@@ -3525,6 +3527,18 @@ static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data _
        if (do_read_u32(ff, &count))
                return -1;
 
+       if (count > MAX_BPF_PROGS) {
+               pr_err("Invalid HEADER_BPF_PROG_INFO: count (%u) > %u\n",
+                      count, MAX_BPF_PROGS);
+               return -1;
+       }
+
+       if (ff->size < sizeof(u32) + count * (2 * sizeof(u32) + sizeof(u64))) {
+               pr_err("Invalid HEADER_BPF_PROG_INFO: section too small (%zu) for %u entries\n",
+                      ff->size, count);
+               return -1;
+       }
+
        down_write(&env->bpf_progs.lock);
 
        for (i = 0; i < count; ++i) {
@@ -3542,6 +3556,12 @@ static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data _
                        goto out;
                }
 
+               if (data_len > MAX_BPF_DATA_LEN) {
+                       pr_warning("Invalid HEADER_BPF_PROG_INFO: data_len (%u) too large\n",
+                                  data_len);
+                       goto out;
+               }
+
                info_linear = malloc(sizeof(struct perf_bpil) +
                                     data_len);
                if (!info_linear)