]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf header: Propagate feature section processing errors
authorArnaldo Carvalho de Melo <acme@redhat.com>
Sat, 2 May 2026 17:24:02 +0000 (14:24 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 29 May 2026 14:44:33 +0000 (11:44 -0300)
perf_session__read_header() discards the return value from
perf_header__process_sections(), so any error from a feature
section processor (process_nrcpus, process_compressed, etc.)
is silently ignored and the session opens as if nothing went
wrong.

This defeats the validation added by subsequent commits in this
series: a crafted perf.data that fails a feature section check
would still be processed with partially-initialized state.

Check the return value and fail the session if any feature
section processor returns an error.

For truncated files (data.size == 0, i.e. recording was
interrupted before the header was finalized), skip feature
section processing entirely and clear the feature bitmap so
tools use their "feature not present" fallbacks instead of
accessing uninitialized env fields.

Change the feature processor stubs for optional libraries
(libtraceevent, libbpf) from returning -1 to returning 0,
so that perf.data files containing these features can still be
opened on builds without the optional library — the feature is
simply skipped rather than causing a fatal error.

Also propagate evlist__prepare_tracepoint_events() failure as
-ENOMEM, since the function can fail due to strdup() allocation
failure inside evsel__prepare_tracepoint_event().

Fixes: 1c0b04d12ae9 ("perf tools: Add perf_session__read_header function")
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Assisted-by: Claude:claude-opus-4.6-1m
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/header.c

index 9e3a08b1f8ae5a73d633fe95162a7cb2939e1175..f4e0e257ff7226ac5b44e96b73ba01f66cdc3992 100644 (file)
@@ -2748,8 +2748,9 @@ static int process_tracing_data(struct feat_fd *ff __maybe_unused, void *data __
 
        return ret < 0 ? -1 : 0;
 #else
-       pr_err("ERROR: Trying to read tracing data without libtraceevent support.\n");
-       return -1;
+       /* Not an error — the feature is simply unsupported in this build */
+       pr_debug("Tracing data present but libtraceevent not available, skipping.\n");
+       return 0;
 #endif
 }
 
@@ -3643,8 +3644,9 @@ out:
        up_write(&env->bpf_progs.lock);
        return err;
 #else
-       pr_err("ERROR: Trying to read bpf_prog_info without libbpf support.\n");
-       return -1;
+       /* Not an error — the feature is simply unsupported in this build */
+       pr_debug("BPF prog info present but libbpf not available, skipping.\n");
+       return 0;
 #endif // HAVE_LIBBPF_SUPPORT
 }
 
@@ -3712,8 +3714,9 @@ out:
        free(node);
        return err;
 #else
-       pr_err("ERROR: Trying to read btf data without libbpf support.\n");
-       return -1;
+       /* Not an error — the feature is simply unsupported in this build */
+       pr_debug("BTF data present but libbpf not available, skipping.\n");
+       return 0;
 #endif // HAVE_LIBBPF_SUPPORT
 }
 
@@ -4900,7 +4903,7 @@ int perf_session__read_header(struct perf_session *session)
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        u64                     f_id;
-       int nr_attrs, nr_ids, i, j, err;
+       int nr_attrs, nr_ids, i, j, err = -ENOMEM;
        int fd = perf_data__fd(data);
 
        session->evlist = evlist__new();
@@ -4920,6 +4923,7 @@ int perf_session__read_header(struct perf_session *session)
                return err;
        }
 
+       err = -ENOMEM;
        if (perf_file_header__read(&f_header, header, fd) < 0)
                return -EINVAL;
 
@@ -4997,15 +5001,36 @@ int perf_session__read_header(struct perf_session *session)
                lseek(fd, tmp, SEEK_SET);
        }
 
+       /*
+        * Skip feature section processing for truncated files
+        * (data.size == 0 means recording was interrupted).  The
+        * section table is unreliable in that case, and the event
+        * data can still be processed without the feature headers.
+        * Clear the bitmap so has_feat() returns false and tools
+        * use their "feature not present" fallbacks instead of
+        * accessing uninitialized env fields.
+        */
+       if (f_header.data.size == 0) {
+               bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
+       } else {
 #ifdef HAVE_LIBTRACEEVENT
-       perf_header__process_sections(header, fd, &session->tevent,
-                                     perf_file_section__process);
+               err = perf_header__process_sections(header, fd, &session->tevent,
+                                                   perf_file_section__process);
+               if (err < 0)
+                       goto out_delete_evlist;
 
-       if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
-               goto out_delete_evlist;
+               if (evlist__prepare_tracepoint_events(session->evlist,
+                                                     session->tevent.pevent)) {
+                       err = -ENOMEM;
+                       goto out_delete_evlist;
+               }
 #else
-       perf_header__process_sections(header, fd, NULL, perf_file_section__process);
+               err = perf_header__process_sections(header, fd, NULL,
+                                                   perf_file_section__process);
+               if (err < 0)
+                       goto out_delete_evlist;
 #endif
+       }
 
        return 0;
 out_errno:
@@ -5014,7 +5039,7 @@ out_errno:
 out_delete_evlist:
        evlist__delete(session->evlist);
        session->evlist = NULL;
-       return -ENOMEM;
+       return err;
 }
 
 int perf_event__process_feature(const struct perf_tool *tool __maybe_unused,