Exploring BPF LSM Support on aarch64 Using ftrace
The article investigates why BPF LSM programs fail to load on aarch64 kernels, uses ftrace‑based tools such as bpftrace and trace‑cmd to trace kernel execution, discovers missing arch_prepare_bpf_trampoline support in 5.15 and 6.1, and shows that a patch merged into the mainline kernel restores functionality for upcoming releases.
Background
The author encountered errors when loading BPF LSM programs on an aarch64 Linux VM (Ubuntu 22.04, kernel 5.15) on a MacBook M2. The same programs work on x86_64, indicating architectural differences in kernel support.
Problem Statement
When attaching a BPF LSM program to the path_mknod hook on aarch64, the pulsar tool reports error codes 524 (ENOTSUPP) or bpf_raw_tracepoint_open failures. The goal is to pinpoint the missing kernel functionality.
Tools Used
bpftrace : a BPF‑based dynamic tracing tool.
trace‑cmd : a wrapper around the tracefs and ftrace infrastructure.
All experiments were performed on a custom Armbian image for a Pine A64.
Investigation on Linux 5.15
Using the probe binary (a simplified test runner) the author recorded the function‑graph of __sys_bpf. The trace‑cmd output showed that the function arch_prepare_bpf_trampoline returned -ENOTSUPP:
int __weak arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr,
void *image, void *image_end,
const struct btf_func_model *m, u32 flags,
struct bpf_tramp_links *tlinks,
void *orig_call)
{
return -ENOTSUPP;
}This weak implementation indicates that the aarch64 architecture lacks support for the trampoline preparation function in kernel 5.15.
Investigation on Linux 6.1
Running the same program on a 6.1 kernel still produced the same error. However, probing arch_prepare_bpf_trampoline with bpftrace now returned a positive value (284), showing that the function no longer fails directly.
The author then used trace‑cmd to capture a narrowed function‑graph focusing on the trampoline registration path. The trace revealed successful calls to arch_prepare_bpf_trampoline, set_memory_ro, and set_memory_x, but the final function in the graph was kallsyms_lookup_size_offset, which is invoked indirectly via ftrace_location inside register_fentry.
Root Cause Analysis
Examining bpf_trampoline_update showed that it calls arch_prepare_bpf_trampoline and then proceeds to set memory permissions before registering the fentry. The registration path eventually calls ftrace_location, which falls back to kallsyms_lookup_size_offset when no ftrace record is found.
The creation of the trampoline structure occurs in bpf_trampoline_lookup. The fops field is allocated only when the kernel configuration flag CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS is enabled. This flag depends on HAVE_CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS, which is not defined for aarch64, leaving tr->fops NULL and causing register_fentry to return -ENOTSUPP.
Patch and Future Support
A patch (referenced as [7] and later merged as [8]) adds the missing direct‑call support for aarch64. The patch has been back‑ported to the 6.x series and is slated for inclusion in the upcoming Linux 6.4 release, enabling BPF LSM on aarch64.
Conclusion
Because aarch64 kernels lack the CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS flag, BPF LSM programs cannot be attached on kernels prior to 6.4. The merged patch restores this capability, allowing LSM hooks to be used on aarch64 in future kernel versions.
Linux Code Review Hub
A professional Linux technology community and learning platform covering the kernel, memory management, process management, file system and I/O, performance tuning, device drivers, virtualization, and cloud computing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
