A proposed patch series for the Linux kernel promises to solve a long-standing limitation for reproducible build systems like Nix and Bazel: the inability to run relocatable binaries without cumbersome wrapper scripts or patching tools. The solution, which uses eBPF to dynamically select a binary's interpreter, emerged from a collaborative effort on the Linux kernel mailing list and is expected to land in the -next branch soon [citation:6][citation:8].
The $ORIGIN challenge in Linux
The core issue lies in how the Linux kernel handles the PT_INTERP segment of an ELF binary. This segment hardcodes the absolute path to the dynamic linker (e.g., /lib64/ld-linux-x86-64.so.2) that the kernel must load to run the program. For package managers like Nix, which store binaries in content-addressed paths that can vary between systems, this creates a significant problem. A binary built on one machine might have a hardcoded path to a loader that doesn't exist on another, causing the execution to fail [citation:8][citation:12].
While the dynamic linker itself supports the $ORIGIN variable to resolve paths relative to the binary's location, the kernel does not expand this variable in PT_INTERP. This forces projects to rely on post-build tools like patchelf to rewrite the interpreter path or to use wrapper scripts that set up the environment before execution [citation:1].
A programmable solution with eBPF
Developer Farid Zakaria initially proposed adding $ORIGIN support directly to the kernel's Virtual File System (VFS). However, Linux VFS maintainer Christian Brauner pushed back on this idea, citing security concerns and potential for loader injection attacks [citation:1]. Instead, Brauner proposed a more flexible and secure alternative: using eBPF (Extended Berkeley Packet Filter) to programmatically select the interpreter via the existing binfmt_misc subsystem [citation:6].
binfmt_misc is a kernel feature that allows administrators to register handlers for arbitrary binary formats, traditionally using fixed magic bytes and interpreter strings. The new patch series, championed by Brauner and now being carried forward by Zakaria, introduces a new handler type ('B') that allows an eBPF program to be registered as the matcher and loader [citation:1][citation:3].
The proposed eBPF program can inspect the binary's header, its full path, or even new ELF segments to determine the correct interpreter on a per-binary basis. A sample program provided in the patch series demonstrates how to read a binary's file path using the bpf_path_d_path() helper and construct a loader path relative to it, effectively supporting the $ORIGIN behavior in the kernel for the first time [citation:8].
Preserving process identity
A critical enhancement in the patch series addresses a side-effect of the traditional binfmt_misc mechanism. Normally, the registered interpreter takes over the process identity, and the original binary becomes its argument. This means tools that rely on /proc/self/exe to find their own location will instead point to the interpreter, which breaks many applications [citation:12].
To solve this, the series introduces new dispatch modes, most notably the 'L' flag for loader substitution. With this flag, the kernel executes the matched binary as the main image and substitutes the chosen eBPF-selected interpreter for the loader in PT_INTERP, preserving the process's identity and making the hand-off transparent [citation:6][citation:12].
What's next for Nix and Linux
The patch series is currently a work-in-progress, but it is being developed on the kernel mailing list and is on track for the -next branch. The plan is to gate this functionality behind a new PT_INTERP_NIX segment, ensuring that the eBPF handler only acts on binaries that explicitly opt-in, leaving standard binaries unaffected [citation:6].
Once the patches land in a stable kernel release, developers plan to upstream a NixOS module to register the eBPF handler automatically at boot. This will allow developers using Nix to produce truly relocatable binaries without patching or wrapper scripts, significantly improving portability and simplifying the build process [citation:12][citation:6].