bpf-util: rename from bpf-dlopen, unify version-specific symbol handling

Renames src/shared/bpf-dlopen.{c,h} to src/shared/bpf-util.{c,h} and
folds the former src/shared/bpf-compat.h (struct forward decl and
compat_bpf_map_create() helper) into the new header.

Aligns dlopen_bpf() with the standard wrapper pattern: drops the
manual dlopen_safe()/dlsym_many_or_warn()/TAKE_PTR(dl) plumbing and
the bespoke 'cached' int in favor of dlopen_many_sym_or_warn() inside
a FOREACH_STRING() soname-fallback loop.

Unifies declaration of the version-specific symbols (bpf_create_map,
bpf_map_create, bpf_object__next_map, bpf_token_create) into a single
DISABLE_WARNING_REDUNDANT_DECLS block in the header, and alphabetically
merges the DLSYM_PROTOTYPE list. DLSYM_OPTIONAL is used to load each
one — call sites already handle NULL (compat_bpf_map_create() and the
sym_bpf_object__next_map guard in userns-restrict.c). bpf_token_create
additionally defaults to a missing_bpf_token_create() stub returning
-ENOSYS, so callers can branch on the errno instead of NULL-checking
the pointer.

Updates test-bpf-token to match: drops the compile-time
LIBBPF_MAJOR_VERSION ≥ 1.5 gate and the direct <bpf/bpf.h> include in
favor of dlopen_bpf() + sym_bpf_token_create(), and treats -ENOSYS as
the test-skip path (covering both 'libbpf too old' and 'kernel lacks
BPF_TOKEN_CREATE support').
This commit is contained in:
Daan De Meyer
2026-05-18 21:17:38 +00:00
parent aa0f03eb03
commit 7d822ca8af
21 changed files with 247 additions and 294 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
* fine given that LGPL-2.1-or-later downgrades to GPL if needed. * fine given that LGPL-2.1-or-later downgrades to GPL if needed.
*/ */
#include "bpf-dlopen.h" /* IWYU pragma: keep */ #include "bpf-util.h" /* IWYU pragma: keep */
/* libbpf is used via dlopen(), so rename symbols */ /* libbpf is used via dlopen(), so rename symbols */
#define bpf_object__attach_skeleton sym_bpf_object__attach_skeleton #define bpf_object__attach_skeleton sym_bpf_object__attach_skeleton
+1 -1
View File
@@ -394,7 +394,7 @@ foreach program : bpf_programs
# Keeping it out of bpf_programs_by_name also keeps it out of the # Keeping it out of bpf_programs_by_name also keeps it out of the
# clang-tidy per-source test loop, which would otherwise fall back # clang-tidy per-source test loop, which would otherwise fall back
# to a BPF compile_commands.json entry (no -Isrc/shared) and fail # to a BPF compile_commands.json entry (no -Isrc/shared) and fail
# to resolve bpf-dlopen.h. # to resolve bpf-util.h.
configure_file( configure_file(
input : 'bpf-skel-wrapper.h.in', input : 'bpf-skel-wrapper.h.in',
output : name + '-skel.h', output : name + '-skel.h',
+1 -1
View File
@@ -12,7 +12,7 @@
#if BPF_FRAMEWORK #if BPF_FRAMEWORK
/* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */ /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-link.h" #include "bpf-link.h"
#include "bind-iface-skel.h" #include "bind-iface-skel.h"
+1 -1
View File
@@ -15,7 +15,7 @@
#if BPF_FRAMEWORK #if BPF_FRAMEWORK
/* libbpf, clang and llc compile time dependencies are satisfied */ /* libbpf, clang and llc compile time dependencies are satisfied */
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-link.h" #include "bpf-link.h"
#include "restrict-fs-skel.h" #include "restrict-fs-skel.h"
+1 -1
View File
@@ -37,7 +37,7 @@ const char* const restrict_fsaccess_link_names[_RESTRICT_FILESYSTEM_ACCESS_LINK_
}; };
#if BPF_FRAMEWORK && HAVE_LSM_INTEGRITY_TYPE #if BPF_FRAMEWORK && HAVE_LSM_INTEGRITY_TYPE
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-link.h" #include "bpf-link.h"
#include "restrict-fsaccess-skel.h" #include "restrict-fsaccess-skel.h"
+1 -1
View File
@@ -14,7 +14,7 @@
#if BPF_FRAMEWORK #if BPF_FRAMEWORK
/* libbpf, clang and llc compile time dependencies are satisfied */ /* libbpf, clang and llc compile time dependencies are satisfied */
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-link.h" #include "bpf-link.h"
#include "restrict-ifaces-skel.h" #include "restrict-ifaces-skel.h"
+1 -1
View File
@@ -9,7 +9,7 @@
#if BPF_FRAMEWORK #if BPF_FRAMEWORK
/* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */ /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-link.h" #include "bpf-link.h"
#include "socket-bind-api.bpf.h" #include "socket-bind-api.bpf.h"
#include "socket-bind-skel.h" #include "socket-bind-skel.h"
+1 -1
View File
@@ -21,7 +21,7 @@
#include "ask-password-api.h" #include "ask-password-api.h"
#include "barrier.h" #include "barrier.h"
#include "bitfield.h" #include "bitfield.h"
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-restrict-fs.h" #include "bpf-restrict-fs.h"
#include "btrfs-util.h" #include "btrfs-util.h"
#include "capability-util.h" #include "capability-util.h"
+1 -1
View File
@@ -5,7 +5,7 @@
#include "sd-messages.h" #include "sd-messages.h"
#include "af-list.h" #include "af-list.h"
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "conf-parser.h" #include "conf-parser.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "cgroup-util.h" #include "cgroup-util.h"
+1 -1
View File
@@ -5,7 +5,7 @@
#include "sd-daemon.h" #include "sd-daemon.h"
#include "bpf-dlopen.h" #include "bpf-util.h"
#if HAVE_VMLINUX_H #if HAVE_VMLINUX_H
#include "bpf-link.h" #include "bpf-link.h"
#include "userns-restrict-skel.h" #include "userns-restrict-skel.h"
+1 -1
View File
@@ -6,7 +6,7 @@
#include "userns-restrict-skel.h" #include "userns-restrict-skel.h"
#endif #endif
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-link.h" #include "bpf-link.h"
#include "fd-util.h" #include "fd-util.h"
#include "log.h" #include "log.h"
-49
View File
@@ -1,49 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <bpf/libbpf.h>
/* libbpf has been moving quickly.
* They added new symbols in the 0.x versions and shortly after removed
* deprecated symbols in 1.0.
* We only need bpf_map_create and libbpf_probe_bpf_prog_type so we work
* around the incompatibility here by:
* - declaring both symbols, and looking for either depending on the libbpf
* so version we found
* - having helpers that automatically use the appropriate version behind the
* new API for easy cleanup later
*
* The advantage of doing this instead of only looking for the symbols declared at
* compile time is that we can then load either the old or the new symbols at runtime
* regardless of the version we were compiled with */
/* declare the struct for libbpf <= 0.6.0 -- it causes no harm on newer versions */
struct bpf_map_create_opts;
/* new symbols available from 0.7.0.
* We need the symbols here:
* - after bpf_map_create_opts struct has been defined for older libbpf
* - before the compat static inline helpers that use them.
* When removing this file move these back to bpf-dlopen.h */
extern int (*sym_bpf_map_create)(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *);
extern struct bpf_map* (*sym_bpf_object__next_map)(const struct bpf_object *obj, const struct bpf_map *map);
/* compat symbols removed in libbpf 1.0 */
extern int (*sym_bpf_create_map)(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags);
/* helpers to use the available variant behind new API */
static inline int compat_bpf_map_create(
enum bpf_map_type map_type,
const char *map_name,
__u32 key_size,
__u32 value_size,
__u32 max_entries,
const struct bpf_map_create_opts *opts) {
if (sym_bpf_map_create)
return sym_bpf_map_create(map_type, map_name, key_size,
value_size, max_entries, opts);
return sym_bpf_create_map(map_type, key_size, value_size, max_entries,
0 /* opts->map_flags, but opts is always NULL for us so skip build dependency on the type */);
}
-221
View File
@@ -1,221 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-dlopen.h"
#include "bpf-dlopen.h"
#include "dlfcn-util.h"
#include "errno-util.h"
#include "initrd-util.h"
#include "log.h"
#if HAVE_LIBBPF
/* libbpf changed types of function prototypes around, so we need to disable some type checking for older
* libbpf. We consider everything older than 0.7 too old for accurate type checks. */
#if defined(__LIBBPF_CURRENT_VERSION_GEQ)
#if __LIBBPF_CURRENT_VERSION_GEQ(0, 7)
#define MODERN_LIBBPF 1
#endif
#endif
#if !defined(MODERN_LIBBPF)
#define MODERN_LIBBPF 0
#endif
static void *bpf_dl = NULL;
static DLSYM_PROTOTYPE(libbpf_get_error) = NULL;
DLSYM_PROTOTYPE(bpf_link__destroy) = NULL;
DLSYM_PROTOTYPE(bpf_link__fd) = NULL;
DLSYM_PROTOTYPE(bpf_link__open) = NULL;
DLSYM_PROTOTYPE(bpf_link__pin) = NULL;
DLSYM_PROTOTYPE(bpf_map__fd) = NULL;
DLSYM_PROTOTYPE(bpf_map__name) = NULL;
DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd) = NULL;
DLSYM_PROTOTYPE(bpf_map__set_max_entries) = NULL;
DLSYM_PROTOTYPE(bpf_map__set_pin_path) = NULL;
DLSYM_PROTOTYPE(bpf_map_delete_elem) = NULL;
DLSYM_PROTOTYPE(bpf_map_get_fd_by_id) = NULL;
DLSYM_PROTOTYPE(bpf_map_lookup_elem) = NULL;
DLSYM_PROTOTYPE(bpf_map_update_elem) = NULL;
DLSYM_PROTOTYPE(bpf_obj_get_info_by_fd) = NULL;
DLSYM_PROTOTYPE(bpf_object__attach_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__destroy_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__detach_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__load_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__name) = NULL;
DLSYM_PROTOTYPE(bpf_object__open_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__pin_maps) = NULL;
DLSYM_PROTOTYPE(bpf_program__attach) = NULL;
DLSYM_PROTOTYPE(bpf_program__attach_cgroup) = NULL;
DLSYM_PROTOTYPE(bpf_program__attach_lsm) = NULL;
DLSYM_PROTOTYPE(bpf_program__name) = NULL;
DLSYM_PROTOTYPE(bpf_program__set_autoload) = NULL;
DLSYM_PROTOTYPE(libbpf_set_print) = NULL;
DLSYM_PROTOTYPE(ring_buffer__epoll_fd) = NULL;
DLSYM_PROTOTYPE(ring_buffer__free) = NULL;
DLSYM_PROTOTYPE(ring_buffer__new) = NULL;
DLSYM_PROTOTYPE(ring_buffer__poll) = NULL;
/* new symbols available from libbpf 0.7.0 */
int (*sym_bpf_map_create)(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *);
struct bpf_map* (*sym_bpf_object__next_map)(const struct bpf_object *obj, const struct bpf_map *map);
/* compat symbols removed in libbpf 1.0 */
int (*sym_bpf_create_map)(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags);
_printf_(2,0)
static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) {
#if !LOG_TRACE
/* libbpf logs a lot of details at its debug level, which we don't need to see. */
if (level == LIBBPF_DEBUG)
return 0;
#endif
/* All other levels are downgraded to LOG_DEBUG */
/* errno is used here, on the assumption that if the log message uses %m, errno will be set to
* something useful. Otherwise, it shouldn't matter, we may pass 0 or some bogus value. */
return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap);
}
int dlopen_bpf(int log_level) {
static int cached = 0;
int r;
if (cached != 0)
return cached;
SD_ELF_NOTE_DLOPEN(
"bpf",
"Support firewalling and sandboxing with BPF",
SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
"libbpf.so.1", "libbpf.so.0");
DISABLE_WARNING_DEPRECATED_DECLARATIONS;
_cleanup_(dlclosep) void *dl = NULL;
r = dlopen_safe("libbpf.so.1", &dl, /* reterr_dlerror= */ NULL);
if (r < 0) {
/* libbpf < 1.0.0 (we rely on 0.1.0+) provide most symbols we care about, but
* unfortunately not all until 0.7.0. See bpf-compat.h for more details.
* Once we consider we can assume 0.7+ is present we can just use the same symbol
* list for both files, and when we assume 1.0+ is present we can remove this dlopen */
const char *dle = NULL;
r = dlopen_safe("libbpf.so.0", &dl, &dle);
if (r < 0) {
log_full_errno(in_initrd() ? LOG_DEBUG : log_level, r,
"Neither libbpf.so.1 nor libbpf.so.0 are installed, cgroup BPF features disabled: %s", dle ?: STRERROR(r));
return (cached = -EOPNOTSUPP); /* turn into recognizable error */
}
log_debug("Loaded 'libbpf.so.0' via dlopen()");
/* symbols deprecated in 1.0 we use as compat */
r = dlsym_many_or_warn(
dl, LOG_DEBUG,
#if MODERN_LIBBPF
/* Don't exist anymore in new libbpf, hence cannot type check them */
DLSYM_ARG_FORCE(bpf_create_map)
#else
DLSYM_ARG(bpf_create_map)
#endif
);
/* NB: we don't try to load bpf_object__next_map() on old versions */
} else {
log_debug("Loaded 'libbpf.so.1' via dlopen()");
/* symbols available from 0.7.0 */
r = dlsym_many_or_warn(
dl, LOG_DEBUG,
#if MODERN_LIBBPF
DLSYM_ARG(bpf_map_create),
DLSYM_ARG(bpf_object__next_map)
#else
/* These symbols did not exist in old libbpf, hence we cannot type check them */
DLSYM_ARG_FORCE(bpf_map_create),
DLSYM_ARG_FORCE(bpf_object__next_map)
#endif
);
}
if (r < 0)
return cached = log_full_errno(log_level, r, "Failed to load libbpf symbols, cgroup BPF features disabled: %m");
r = dlsym_many_or_warn(
dl, LOG_DEBUG,
DLSYM_ARG(bpf_link__destroy),
DLSYM_ARG(bpf_link__fd),
DLSYM_ARG(bpf_link__open),
DLSYM_ARG(bpf_link__pin),
DLSYM_ARG(bpf_map__fd),
DLSYM_ARG(bpf_map__name),
DLSYM_ARG(bpf_map__set_inner_map_fd),
DLSYM_ARG(bpf_map__set_max_entries),
DLSYM_ARG(bpf_map__set_pin_path),
DLSYM_ARG(bpf_map_delete_elem),
DLSYM_ARG(bpf_map_get_fd_by_id),
DLSYM_ARG(bpf_map_lookup_elem),
DLSYM_ARG(bpf_map_update_elem),
DLSYM_ARG(bpf_obj_get_info_by_fd),
DLSYM_ARG(bpf_object__attach_skeleton),
DLSYM_ARG(bpf_object__destroy_skeleton),
DLSYM_ARG(bpf_object__detach_skeleton),
DLSYM_ARG(bpf_object__load_skeleton),
DLSYM_ARG(bpf_object__name),
DLSYM_ARG(bpf_object__open_skeleton),
DLSYM_ARG(bpf_object__pin_maps),
#if MODERN_LIBBPF
DLSYM_ARG(bpf_program__attach),
DLSYM_ARG(bpf_program__attach_cgroup),
DLSYM_ARG(bpf_program__attach_lsm),
#else
/* libbpf added a "const" to function parameters where it should not have, ignore this type incompatibility */
DLSYM_ARG_FORCE(bpf_program__attach),
DLSYM_ARG_FORCE(bpf_program__attach_cgroup),
DLSYM_ARG_FORCE(bpf_program__attach_lsm),
#endif
DLSYM_ARG(bpf_program__name),
DLSYM_ARG(bpf_program__set_autoload),
DLSYM_ARG(libbpf_get_error),
DLSYM_ARG(libbpf_set_print),
DLSYM_ARG(ring_buffer__epoll_fd),
DLSYM_ARG(ring_buffer__free),
DLSYM_ARG(ring_buffer__new),
DLSYM_ARG(ring_buffer__poll));
if (r < 0)
return cached = log_full_errno(log_level, r, "Failed to load libbpf symbols, cgroup BPF features disabled: %m");
/* We set the print helper unconditionally. Otherwise libbpf will emit not useful log messages. */
(void) sym_libbpf_set_print(bpf_print_func);
REENABLE_WARNING;
bpf_dl = TAKE_PTR(dl);
return cached = true;
}
int bpf_get_error_translated(const void *ptr) {
int r;
r = sym_libbpf_get_error(ptr);
switch (r) {
case -524:
/* Workaround for kernel bug, BPF returns an internal error instead of translating it, until
* it is fixed:
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/errno.h?h=v6.9&id=a38297e3fb012ddfa7ce0321a7e5a8daeb1872b6#n27
*/
return -EOPNOTSUPP;
default:
return r;
}
}
#else
int dlopen_bpf(int log_level) {
return log_once_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
"libbpf support is not compiled in, cgroup BPF features disabled.");
}
#endif
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "bpf-link.h" #include "bpf-link.h"
#include "serialize.h" #include "serialize.h"
+178
View File
@@ -0,0 +1,178 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-dlopen.h"
#include "bpf-util.h"
#include "dlfcn-util.h"
#include "initrd-util.h"
#include "log.h"
#include "strv.h"
#if HAVE_LIBBPF
/* libbpf changed types of function prototypes around, so we need to disable some type checking for older
* libbpf. We consider everything older than 0.7 too old for accurate type checks. */
#if defined(__LIBBPF_CURRENT_VERSION_GEQ)
#if __LIBBPF_CURRENT_VERSION_GEQ(0, 7)
#define MODERN_LIBBPF 1
#endif
#endif
#if !defined(MODERN_LIBBPF)
#define MODERN_LIBBPF 0
#endif
static DLSYM_PROTOTYPE(libbpf_get_error) = NULL;
DLSYM_PROTOTYPE(bpf_create_map) = NULL;
DLSYM_PROTOTYPE(bpf_link__destroy) = NULL;
DLSYM_PROTOTYPE(bpf_link__fd) = NULL;
DLSYM_PROTOTYPE(bpf_link__open) = NULL;
DLSYM_PROTOTYPE(bpf_link__pin) = NULL;
DLSYM_PROTOTYPE(bpf_map__fd) = NULL;
DLSYM_PROTOTYPE(bpf_map__name) = NULL;
DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd) = NULL;
DLSYM_PROTOTYPE(bpf_map__set_max_entries) = NULL;
DLSYM_PROTOTYPE(bpf_map__set_pin_path) = NULL;
DLSYM_PROTOTYPE(bpf_map_create) = NULL;
DLSYM_PROTOTYPE(bpf_map_delete_elem) = NULL;
DLSYM_PROTOTYPE(bpf_map_get_fd_by_id) = NULL;
DLSYM_PROTOTYPE(bpf_map_lookup_elem) = NULL;
DLSYM_PROTOTYPE(bpf_map_update_elem) = NULL;
DLSYM_PROTOTYPE(bpf_obj_get_info_by_fd) = NULL;
DLSYM_PROTOTYPE(bpf_object__attach_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__destroy_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__detach_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__load_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__name) = NULL;
DLSYM_PROTOTYPE(bpf_object__next_map) = NULL;
DLSYM_PROTOTYPE(bpf_object__open_skeleton) = NULL;
DLSYM_PROTOTYPE(bpf_object__pin_maps) = NULL;
DLSYM_PROTOTYPE(bpf_program__attach) = NULL;
DLSYM_PROTOTYPE(bpf_program__attach_cgroup) = NULL;
DLSYM_PROTOTYPE(bpf_program__attach_lsm) = NULL;
DLSYM_PROTOTYPE(bpf_program__name) = NULL;
DLSYM_PROTOTYPE(bpf_program__set_autoload) = NULL;
static int missing_bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts) {
return -ENOSYS;
}
DLSYM_PROTOTYPE(bpf_token_create) = missing_bpf_token_create;
DLSYM_PROTOTYPE(libbpf_set_print) = NULL;
DLSYM_PROTOTYPE(ring_buffer__epoll_fd) = NULL;
DLSYM_PROTOTYPE(ring_buffer__free) = NULL;
DLSYM_PROTOTYPE(ring_buffer__new) = NULL;
DLSYM_PROTOTYPE(ring_buffer__poll) = NULL;
_printf_(2,0)
static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) {
#if !LOG_TRACE
/* libbpf logs a lot of details at its debug level, which we don't need to see. */
if (level == LIBBPF_DEBUG)
return 0;
#endif
/* All other levels are downgraded to LOG_DEBUG */
/* errno is used here, on the assumption that if the log message uses %m, errno will be set to
* something useful. Otherwise, it shouldn't matter, we may pass 0 or some bogus value. */
return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap);
}
int dlopen_bpf(int log_level) {
static void *bpf_dl = NULL;
int r;
SD_ELF_NOTE_DLOPEN(
"bpf",
"Support firewalling and sandboxing with BPF",
SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
"libbpf.so.1", "libbpf.so.0");
DISABLE_WARNING_DEPRECATED_DECLARATIONS;
FOREACH_STRING(soname, "libbpf.so.1", "libbpf.so.0") {
r = dlopen_many_sym_or_warn(
&bpf_dl, soname, LOG_DEBUG,
DLSYM_ARG(bpf_link__destroy),
DLSYM_ARG(bpf_link__fd),
DLSYM_ARG(bpf_link__open),
DLSYM_ARG(bpf_link__pin),
DLSYM_ARG(bpf_map__fd),
DLSYM_ARG(bpf_map__name),
DLSYM_ARG(bpf_map__set_inner_map_fd),
DLSYM_ARG(bpf_map__set_max_entries),
DLSYM_ARG(bpf_map__set_pin_path),
DLSYM_ARG(bpf_map_delete_elem),
DLSYM_ARG(bpf_map_get_fd_by_id),
DLSYM_ARG(bpf_map_lookup_elem),
DLSYM_ARG(bpf_map_update_elem),
DLSYM_ARG(bpf_obj_get_info_by_fd),
DLSYM_ARG(bpf_object__attach_skeleton),
DLSYM_ARG(bpf_object__destroy_skeleton),
DLSYM_ARG(bpf_object__detach_skeleton),
DLSYM_ARG(bpf_object__load_skeleton),
DLSYM_ARG(bpf_object__name),
DLSYM_ARG(bpf_object__open_skeleton),
DLSYM_ARG(bpf_object__pin_maps),
#if MODERN_LIBBPF
DLSYM_ARG(bpf_program__attach),
DLSYM_ARG(bpf_program__attach_cgroup),
DLSYM_ARG(bpf_program__attach_lsm),
#else
/* libbpf added a "const" to function parameters where it should not have, ignore this type incompatibility */
DLSYM_ARG_FORCE(bpf_program__attach),
DLSYM_ARG_FORCE(bpf_program__attach_cgroup),
DLSYM_ARG_FORCE(bpf_program__attach_lsm),
#endif
DLSYM_ARG(bpf_program__name),
DLSYM_ARG(bpf_program__set_autoload),
DLSYM_ARG(libbpf_get_error),
DLSYM_ARG(libbpf_set_print),
DLSYM_ARG(ring_buffer__epoll_fd),
DLSYM_ARG(ring_buffer__free),
DLSYM_ARG(ring_buffer__new),
DLSYM_ARG(ring_buffer__poll));
if (r >= 0)
break;
}
REENABLE_WARNING;
if (r < 0)
return log_full_errno(in_initrd() ? LOG_DEBUG : log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
"Neither libbpf.so.1 nor libbpf.so.0 are installed, cgroup BPF features disabled.");
/* Version-specific symbols: bpf_create_map exists only in libbpf < 1.0; bpf_map_create and
* bpf_object__next_map only in 0.7+. bpf_token_create only in 1.5+. Unresolved prototypes keep
* their initializers (NULL, or a fallback returning -ENOSYS for bpf_token_create). */
DLSYM_OPTIONAL(bpf_dl, bpf_create_map);
DLSYM_OPTIONAL(bpf_dl, bpf_map_create);
DLSYM_OPTIONAL(bpf_dl, bpf_object__next_map);
DLSYM_OPTIONAL(bpf_dl, bpf_token_create);
/* We set the print helper unconditionally. Otherwise libbpf will emit not useful log messages. */
(void) sym_libbpf_set_print(bpf_print_func);
return 1;
}
int bpf_get_error_translated(const void *ptr) {
int r;
r = sym_libbpf_get_error(ptr);
switch (r) {
case -524:
/* Workaround for kernel bug, BPF returns an internal error instead of translating it, until
* it is fixed:
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/errno.h?h=v6.9&id=a38297e3fb012ddfa7ce0321a7e5a8daeb1872b6#n27
*/
return -EOPNOTSUPP;
default:
return r;
}
}
#else
int dlopen_bpf(int log_level) {
return log_once_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
"libbpf support is not compiled in, cgroup BPF features disabled.");
}
#endif
@@ -8,10 +8,27 @@
#include <bpf/bpf.h> /* IWYU pragma: export */ #include <bpf/bpf.h> /* IWYU pragma: export */
#include <bpf/libbpf.h> /* IWYU pragma: export */ #include <bpf/libbpf.h> /* IWYU pragma: export */
#include "bpf-compat.h" /* IWYU pragma: export */
#include "dlfcn-util.h" #include "dlfcn-util.h"
#include "shared-forward.h" #include "shared-forward.h"
/* Always redeclare these so DLSYM_PROTOTYPE's typeof() resolves regardless of libbpf version;
* suppress the warning when the libbpf headers already declare them.
* - bpf_map_create, bpf_object__next_map: available since libbpf 0.7
* - bpf_token_create: available since libbpf 1.5
* - bpf_create_map: removed in libbpf 1.0
*/
DISABLE_WARNING_REDUNDANT_DECLS;
/* NOLINTBEGIN(readability-redundant-declaration) */
struct bpf_map_create_opts;
struct bpf_token_create_opts;
extern int bpf_create_map(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags);
extern int bpf_map_create(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *);
extern struct bpf_map* bpf_object__next_map(const struct bpf_object *obj, const struct bpf_map *map);
extern int bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts);
/* NOLINTEND(readability-redundant-declaration) */
REENABLE_WARNING;
extern DLSYM_PROTOTYPE(bpf_create_map);
extern DLSYM_PROTOTYPE(bpf_link__destroy); extern DLSYM_PROTOTYPE(bpf_link__destroy);
extern DLSYM_PROTOTYPE(bpf_link__fd); extern DLSYM_PROTOTYPE(bpf_link__fd);
extern DLSYM_PROTOTYPE(bpf_link__open); extern DLSYM_PROTOTYPE(bpf_link__open);
@@ -21,6 +38,7 @@ extern DLSYM_PROTOTYPE(bpf_map__name);
extern DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd); extern DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd);
extern DLSYM_PROTOTYPE(bpf_map__set_max_entries); extern DLSYM_PROTOTYPE(bpf_map__set_max_entries);
extern DLSYM_PROTOTYPE(bpf_map__set_pin_path); extern DLSYM_PROTOTYPE(bpf_map__set_pin_path);
extern DLSYM_PROTOTYPE(bpf_map_create);
extern DLSYM_PROTOTYPE(bpf_map_delete_elem); extern DLSYM_PROTOTYPE(bpf_map_delete_elem);
extern DLSYM_PROTOTYPE(bpf_map_get_fd_by_id); extern DLSYM_PROTOTYPE(bpf_map_get_fd_by_id);
extern DLSYM_PROTOTYPE(bpf_map_lookup_elem); extern DLSYM_PROTOTYPE(bpf_map_lookup_elem);
@@ -33,6 +51,7 @@ extern DLSYM_PROTOTYPE(bpf_object__destroy_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__detach_skeleton); extern DLSYM_PROTOTYPE(bpf_object__detach_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__load_skeleton); extern DLSYM_PROTOTYPE(bpf_object__load_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__name); extern DLSYM_PROTOTYPE(bpf_object__name);
extern DLSYM_PROTOTYPE(bpf_object__next_map);
extern DLSYM_PROTOTYPE(bpf_object__open_skeleton); extern DLSYM_PROTOTYPE(bpf_object__open_skeleton);
extern DLSYM_PROTOTYPE(bpf_object__pin_maps); extern DLSYM_PROTOTYPE(bpf_object__pin_maps);
extern DLSYM_PROTOTYPE(bpf_program__attach); extern DLSYM_PROTOTYPE(bpf_program__attach);
@@ -40,12 +59,30 @@ extern DLSYM_PROTOTYPE(bpf_program__attach_cgroup);
extern DLSYM_PROTOTYPE(bpf_program__attach_lsm); extern DLSYM_PROTOTYPE(bpf_program__attach_lsm);
extern DLSYM_PROTOTYPE(bpf_program__name); extern DLSYM_PROTOTYPE(bpf_program__name);
extern DLSYM_PROTOTYPE(bpf_program__set_autoload); extern DLSYM_PROTOTYPE(bpf_program__set_autoload);
extern DLSYM_PROTOTYPE(bpf_token_create);
extern DLSYM_PROTOTYPE(libbpf_set_print); extern DLSYM_PROTOTYPE(libbpf_set_print);
extern DLSYM_PROTOTYPE(ring_buffer__epoll_fd); extern DLSYM_PROTOTYPE(ring_buffer__epoll_fd);
extern DLSYM_PROTOTYPE(ring_buffer__free); extern DLSYM_PROTOTYPE(ring_buffer__free);
extern DLSYM_PROTOTYPE(ring_buffer__new); extern DLSYM_PROTOTYPE(ring_buffer__new);
extern DLSYM_PROTOTYPE(ring_buffer__poll); extern DLSYM_PROTOTYPE(ring_buffer__poll);
/* Helper that uses the available variant behind the new API. */
static inline int compat_bpf_map_create(
enum bpf_map_type map_type,
const char *map_name,
__u32 key_size,
__u32 value_size,
__u32 max_entries,
const struct bpf_map_create_opts *opts) {
if (sym_bpf_map_create)
return sym_bpf_map_create(map_type, map_name, key_size,
value_size, max_entries, opts);
return sym_bpf_create_map(map_type, key_size, value_size, max_entries,
0 /* opts->map_flags, but opts is always NULL for us so skip build dependency on the type */);
}
/* libbpf sometimes returns error codes that make sense only in the kernel, like 524 for EOPNOTSUPP. Use /* libbpf sometimes returns error codes that make sense only in the kernel, like 524 for EOPNOTSUPP. Use
* this helper instead of libbpf_get_error() to ensure some of the known ones are translated into errnos * this helper instead of libbpf_get_error() to ensure some of the known ones are translated into errnos
* we understand. */ * we understand. */
+1 -1
View File
@@ -19,8 +19,8 @@ shared_sources = files(
'boot-entry.c', 'boot-entry.c',
'boot-timestamps.c', 'boot-timestamps.c',
'bootspec.c', 'bootspec.c',
'bpf-dlopen.c',
'bpf-program.c', 'bpf-program.c',
'bpf-util.c',
'bridge-util.c', 'bridge-util.c',
'btrfs-util.c', 'btrfs-util.c',
'bus-get-properties.c', 'bus-get-properties.c',
+1 -1
View File
@@ -554,7 +554,7 @@ executables += [
}, },
core_test_template + { core_test_template + {
'sources' : files('test-bpf-token.c'), 'sources' : files('test-bpf-token.c'),
'dependencies' : common_test_dependencies + libbpf, 'dependencies' : common_test_dependencies + libbpf_cflags,
'conditions' : ['BPF_FRAMEWORK'], 'conditions' : ['BPF_FRAMEWORK'],
'type' : 'manual', 'type' : 'manual',
}, },
+1 -1
View File
@@ -92,7 +92,7 @@ static int do_mprotect_exec(const char *path) {
} }
#if BPF_FRAMEWORK && HAVE_LSM_INTEGRITY_TYPE #if BPF_FRAMEWORK && HAVE_LSM_INTEGRITY_TYPE
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "restrict-fsaccess-skel.h" #include "restrict-fsaccess-skel.h"
static struct restrict_fsaccess_bpf *restrict_fsaccess_bpf_free(struct restrict_fsaccess_bpf *obj) { static struct restrict_fsaccess_bpf *restrict_fsaccess_bpf_free(struct restrict_fsaccess_bpf *obj) {
+15 -7
View File
@@ -1,26 +1,34 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <bpf/bpf.h>
#include <fcntl.h> #include <fcntl.h>
#include "bpf-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "main-func.h" #include "main-func.h"
#include "tests.h" /* NOLINT(misc-include-cleaner): this is needed conditionally */ #include "tests.h"
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
#if defined(LIBBPF_MAJOR_VERSION) && (LIBBPF_MAJOR_VERSION > 1 || (LIBBPF_MAJOR_VERSION == 1 && LIBBPF_MINOR_VERSION >= 5)) #if HAVE_LIBBPF
_cleanup_close_ int bpffs_fd = open("/sys/fs/bpf", O_RDONLY); int r;
r = dlopen_bpf(LOG_ERR);
if (r < 0)
return r;
_cleanup_close_ int bpffs_fd = open("/sys/fs/bpf", O_CLOEXEC|O_RDONLY);
if (bpffs_fd < 0) if (bpffs_fd < 0)
return log_error_errno(errno, "Failed to open '/sys/fs/bpf': %m"); return log_error_errno(errno, "Failed to open '/sys/fs/bpf': %m");
_cleanup_close_ int token_fd = bpf_token_create(bpffs_fd, /* opts= */ NULL); _cleanup_close_ int token_fd = sym_bpf_token_create(bpffs_fd, /* opts= */ NULL);
if (token_fd == -ENOSYS)
return log_tests_skipped("bpf_token_create() unavailable (libbpf too old or kernel lacks BPF_TOKEN_CREATE support)");
if (token_fd < 0) if (token_fd < 0)
return log_error_errno(errno, "Failed to create bpf token: %m"); return log_error_errno(token_fd, "Failed to create bpf token: %m");
log_info("Successfully created token fd."); log_info("Successfully created token fd.");
return 0; return 0;
#else #else
return log_tests_skipped("libbpf is older than v1.5"); return log_tests_skipped("BPF framework support is disabled");
#endif #endif
} }
+1 -1
View File
@@ -3,7 +3,7 @@
#include "acl-util.h" #include "acl-util.h"
#include "apparmor-util.h" #include "apparmor-util.h"
#include "blkid-util.h" #include "blkid-util.h"
#include "bpf-dlopen.h" #include "bpf-util.h"
#include "compress.h" #include "compress.h"
#include "crypto-util.h" #include "crypto-util.h"
#include "cryptsetup-util.h" #include "cryptsetup-util.h"