Skip to content

Commit

Permalink
Fix eBPF skeletons for perf trace 6.11+
Browse files Browse the repository at this point in the history
This fixes only versions 6.11 and up.

Perf trace tries to make use of eBPF to trace and extract parameters of
some syscalls (openat, connect, ...).
Take a look inside tools/perf/utils/bpf_skel/augmented_raw_syscalls.bpf.c

In order to build bpf skeletons clang is required.
During build process make tries to compile an example bpf program to test
if tools required work (clang-bpf-co-re).
Script responsible for that suppresses any warning and error that would show the issue.
Enabling those and inspecting the logs we can learn that
clang --target=bpf doesn't support zerocallusedregs hardening option.

In version 6.12
during execution perf trace fails to load bpf program.
Patch provided by Howard Chu ([email protected]) in
https://lore.kernel.org/all/[email protected]/
fixes the issue.
  • Loading branch information
lopk committed Jan 9, 2025
1 parent 4a4790f commit 0f38e97
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
18 changes: 18 additions & 0 deletions pkgs/os-specific/linux/kernel/perf/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
zstd,
withLibcap ? true,
libcap,
buildPackages,
writeShellScript,
}:
let
d3-flame-graph-templates = stdenv.mkDerivation rec {
Expand All @@ -54,6 +56,15 @@ let
install -D -m 0755 -t $out/share/d3-flame-graph/ ./dist/templates/*
'';
};
# The cc-wrapper adds `-fzero-call-used-regs` as part of the default
# hardening to the compiler command line, but clang aborts with an error when
# that is used together with a target arch that is not x86 or x86_64.
# This wrapper works around that issue by instructing the machinery to not
# add that flag for those particular invocations.
clang-bpf = writeShellScript "clang-bpf" ''
NIX_HARDENING_ENABLE=''${NIX_HARDENING_ENABLE/zerocallusedregs/}
exec ${lib.getExe buildPackages.clang} "$@"
'';
in

stdenv.mkDerivation {
Expand All @@ -78,13 +89,19 @@ stdenv.mkDerivation {
url = "https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/patch/?id=1d302f626c2a23e4fd05bb810eff300e8f2174fd";
hash = "sha256-KhCmof8LkyTcBBpfMEtolL3m3kmC5rukKzQvufVKCdI=";
})
]
++ lib.optionals (lib.versions.majorMinor kernel.version == "6.12") [
./fix-augmented-raw-syscalls.bpf.diff # Loading this bpf object can fail with E2BIG in perf trace without the fix
];

postPatch =
''
# Linux scripts
patchShebangs scripts
patchShebangs tools/perf/check-headers.sh
# Expose warnings and errors of feature detection
sed -i -e 's/2>\/dev\/null//g' tools/build/Makefile.feature
''
+ lib.optionalString (lib.versionAtLeast kernel.version "6.3") ''
# perf-specific scripts
Expand Down Expand Up @@ -113,6 +130,7 @@ stdenv.mkDerivation {
"prefix=$(out)"
"WERROR=0"
"ASCIIDOC8=1"
"CLANG=${clang-bpf}"
]
++ kernel.makeFlags
++ lib.optional (!withGtk) "NO_GTK2=1"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--- a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
+++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
@@ -431,9 +431,9 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid)
static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
{
bool augmented, do_output = false;
- int zero = 0, size, aug_size, index,
- value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value);
+ int zero = 0, index, value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value);
u64 output = 0; /* has to be u64, otherwise it won't pass the verifier */
+ s64 aug_size, size;
unsigned int nr, *beauty_map;
struct beauty_payload_enter *payload;
void *arg, *payload_offset;
@@ -484,14 +484,11 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
} else if (size > 0 && size <= value_size) { /* struct */
if (!bpf_probe_read_user(((struct augmented_arg *)payload_offset)->value, size, arg))
augmented = true;
- } else if (size < 0 && size >= -6) { /* buffer */
+ } else if ((int)size < 0 && size >= -6) { /* buffer */
index = -(size + 1);
barrier_var(index); // Prevent clang (noticed with v18) from removing the &= 7 trick.
index &= 7; // Satisfy the bounds checking with the verifier in some kernels.
- aug_size = args->args[index];
-
- if (aug_size > TRACE_AUG_MAX_BUF)
- aug_size = TRACE_AUG_MAX_BUF;
+ aug_size = args->args[index] > TRACE_AUG_MAX_BUF ? TRACE_AUG_MAX_BUF : args->args[index];

if (aug_size > 0) {
if (!bpf_probe_read_user(((struct augmented_arg *)payload_offset)->value, aug_size, arg))

0 comments on commit 0f38e97

Please sign in to comment.