[Bug]: ebpf.plugin crashes in bpf_object__close() when an eBPF object cannot be opened (legacy libbpf 0.0.9 builds)
Bug description
ebpf_load_program() (src/collectors/ebpf.plugin/libbpf_api/ebpf.c) closes the result of a failed bpf_object__open_file():
*obj = bpf_object__open_file(lpath, NULL);
if (!*obj) {
*obj = NULL;
return NULL;
}
if (libbpf_get_error(*obj)) {
bpf_object__close(*obj); // crashes with libbpf 0.0.9
*obj = NULL;
return NULL;
}- With the bundled libbpf 1.x, a failed open returns NULL, so this branch is never reached.
- With the legacy libbpf 0.0.9, a failed open returns an error pointer (
ERR_PTR(-errno)). - 0.0.9's
bpf_object__close()only checks for NULL and then dereferences the pointer, so the plugin segfaults.
On a build with the legacy libbpf, ebpf.plugin --unittest crashes in its fake-binary step (loading a file that doesn't exist):
libbpf: failed to open /usr/libexec/netdata/plugins.d/ebpf.d/rnetdata_ebpf_I_am_not_here.5.10.o: No such file or directory
Program received signal SIGSEGV, Segmentation fault.
0x000055555562caa1 in bpf_object__close (obj=0xfffffffffffffffe) at libbpf.c:6362
6362 if (obj->clear_priv)
#0 bpf_object__close (obj=0xfffffffffffffffe) at libbpf.c:6362
#1 ebpf_load_program (...) at src/collectors/ebpf.plugin/libbpf_api/ebpf.c:974
#2 ebpf_ut_load_binary () at src/collectors/ebpf.plugin/ebpf_unittest.c:70
#3 ebpf_ut_load_fake_binary () at src/collectors/ebpf.plugin/ebpf_unittest.c:107
#4 ebpf_parse_args (argc=2, ...) at src/collectors/ebpf.plugin/ebpf.c:1255
#5 main (...)The kernel logged segfault at 18e: -2 (-ENOENT) + 0x190 (the offset of clear_priv).
Which builds are affected. Netdata builds the bundled libbpf 0.0.9 instead of 1.x when:
-DFORCE_LEGACY_LIBBPF=Onis set; or- the build host's kernel is older than 4.14 (
_need_legacy_libbpf()inpackaging/cmake/Modules/NetdataLibBPF.cmake), for example a source build on CentOS/RHEL 7.
Official packages use libbpf 1.x and are not affected.
Impact on those builds. Any legacy eBPF object that can't be opened crashes the whole plugin instead of disabling one module. For example: a missing file, a kernel-version mapping without an object, or a wrong plugins directory. Reproduced on the system below with the mount module and a plugins directory without objects: the plugin segfaults (exit 139) right after libbpf: failed to open …/ebpf.d/rnetdata_ebpf_mount.5.4.o: No such file or directory.
History. This is the same error pointer as #12233 (2022), whose backtrace shows ebpf_update_map_sizes (program=0xfffffffffffffffe).
- At that time the check was
libbpf_get_error(obj), which tests the address of the variable, so the error was never detected and the pointer was used later. - #21676 corrected the check to
libbpf_get_error(*obj)but kept thebpf_object__close(*obj), so the crash moved intobpf_object__close().
Expected behavior
A failed bpf_object__open_file() makes ebpf_load_program() return NULL.
- The module fails to load, with the existing error message.
- The plugin keeps running its other modules, or shuts down cleanly if none could be loaded.
ebpf.plugin --unittestexits 0.
Steps to reproduce
- Build netdata from source with
-DFORCE_LEGACY_LIBBPF=On, or on a host with a kernel older than 4.14. - Run the mount module with a plugins directory that has no eBPF objects:
sudo env NETDATA_PLUGINS_DIR=$(mktemp -d) ./ebpf.plugin 1 --mountResult:libbpf: failed to open <dir>/ebpf.d/rnetdata_ebpf_mount.5.4.o: No such file or directory, then SIGSEGV (exit 139). - Alternatively, run
sudo env NETDATA_PLUGINS_DIR=/usr/libexec/netdata/plugins.d ./ebpf.plugin --unittest. It segfaults in the fake-binary step. On current master,--unittestonly reaches its steps with the option-dispatch fix, see #24062 and #24063.
Installation method
from source
System info
Linux <hostname> 7.0.0-31-generic #31-Ubuntu SMP PREEMPT_DYNAMIC Sat Aug 1 04:26:38 UTC 2026 x86_64 GNU/Linux
/etc/lsb-release:DISTRIB_ID=Ubuntu
/etc/lsb-release:DISTRIB_RELEASE=26.04
/etc/lsb-release:DISTRIB_CODENAME=resolute
/etc/lsb-release:DISTRIB_DESCRIPTION="Ubuntu 26.04.1 LTS"
/etc/os-release:PRETTY_NAME="Ubuntu 26.04.1 LTS"
/etc/os-release:NAME="Ubuntu"
/etc/os-release:VERSION_ID="26.04"
/etc/os-release:VERSION="26.04.1 LTS (Resolute Raccoon)"
/etc/os-release:VERSION_CODENAME=resolute
/etc/os-release:ID=ubuntu
/etc/os-release:ID_LIKE=debian
/etc/os-release:UBUNTU_CODENAME=resolute
/etc/os-release:LOGO=ubuntu-logoNetdata build info
Source build of the ebpf.plugin target only (netdata -W buildinfo does not apply).
Commit: 667d823b2 (master 4464a9ed7 + the option-dispatch fix, needed for --unittest)
Configure: cmake -DFORCE_LEGACY_LIBBPF=On -DDEFAULT_FEATURE_STATE=Off -DENABLE_PLUGIN_EBPF=On -DENABLE_DASHBOARD=Off
-DENABLE_LEGACY_EBPF_PROGRAMS=Off -DENABLE_PLUGIN_GO=Off -DENABLE_PLUGIN_SCRIPTS=Off
libbpf: bundled v0.0.9_netdata-1 (673424c56127bb556e64095f41fd60c26f9083ec)
Compiler: gcc 15.2.0Additional info
No response
Source: netdata/netdata