Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf bpf-filter: Improve error messages

The BPF filter needs libbpf/BPF-skeleton support and root privilege.
Add error messages to help users understand the problem easily.

When it's not build with BPF support (make BUILD_BPF_SKEL=0).

$ sudo perf record -e cycles --filter "pid != 0" true
Error: BPF filter is requested but perf is not built with BPF.
Please make sure to build with libbpf and BPF skeleton.

Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]

--filter <filter>
event filter

When it supports BPF but runs without root or CAP_BPF. Note that it
also checks pinned BPF filters.

$ perf record -e cycles --filter "pid != 0" -o /dev/null true
Error: BPF filter only works for users with the CAP_BPF capability!
Please run 'perf record --setup-filter pin' as root first.

Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]

--filter <filter>
event filter

Reviewed-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250604174835.1852481-1-namhyung@kernel.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

+36 -1
+28
tools/perf/util/bpf-filter.c
··· 52 52 #include <internal/xyarray.h> 53 53 #include <perf/threadmap.h> 54 54 55 + #include "util/cap.h" 55 56 #include "util/debug.h" 56 57 #include "util/evsel.h" 57 58 #include "util/target.h" ··· 619 618 return expr; 620 619 } 621 620 621 + static bool check_bpf_filter_capable(void) 622 + { 623 + bool used_root; 624 + 625 + if (perf_cap__capable(CAP_BPF, &used_root)) 626 + return true; 627 + 628 + if (!used_root) { 629 + /* Check if root already pinned the filter programs and maps */ 630 + int fd = get_pinned_fd("filters"); 631 + 632 + if (fd >= 0) { 633 + close(fd); 634 + return true; 635 + } 636 + } 637 + 638 + pr_err("Error: BPF filter only works for %s!\n" 639 + "\tPlease run 'perf record --setup-filter pin' as root first.\n", 640 + used_root ? "root" : "users with the CAP_BPF capability"); 641 + 642 + return false; 643 + } 644 + 622 645 int perf_bpf_filter__parse(struct list_head *expr_head, const char *str) 623 646 { 624 647 YY_BUFFER_STATE buffer; 625 648 int ret; 649 + 650 + if (!check_bpf_filter_capable()) 651 + return -EPERM; 626 652 627 653 buffer = perf_bpf_filter__scan_string(str); 628 654
+3
tools/perf/util/bpf-filter.h
··· 5 5 #include <linux/list.h> 6 6 7 7 #include "bpf_skel/sample-filter.h" 8 + #include "util/debug.h" 8 9 9 10 struct perf_bpf_filter_expr { 10 11 struct list_head list; ··· 39 38 static inline int perf_bpf_filter__parse(struct list_head *expr_head __maybe_unused, 40 39 const char *str __maybe_unused) 41 40 { 41 + pr_err("Error: BPF filter is requested but perf is not built with BPF.\n" 42 + "\tPlease make sure to build with libbpf and BPF skeleton.\n"); 42 43 return -EOPNOTSUPP; 43 44 } 44 45 static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused,
-1
tools/perf/util/cap.c
··· 7 7 #include "debug.h" 8 8 #include <errno.h> 9 9 #include <string.h> 10 - #include <linux/capability.h> 11 10 #include <sys/syscall.h> 12 11 #include <unistd.h> 13 12
+5
tools/perf/util/cap.h
··· 3 3 #define __PERF_CAP_H 4 4 5 5 #include <stdbool.h> 6 + #include <linux/capability.h> 6 7 7 8 /* For older systems */ 8 9 #ifndef CAP_SYSLOG ··· 12 11 13 12 #ifndef CAP_PERFMON 14 13 #define CAP_PERFMON 38 14 + #endif 15 + 16 + #ifndef CAP_BPF 17 + #define CAP_BPF 39 15 18 #endif 16 19 17 20 /* Query if a capability is supported, used_root is set if the fallback root check was used. */