core/bpf: drop old kernels support (#37151)
This commit is contained in:
@@ -26,12 +26,10 @@ struct bpf_map_create_opts;
|
||||
* - 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 int (*sym_libbpf_probe_bpf_prog_type)(enum bpf_prog_type, const void *);
|
||||
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);
|
||||
extern bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
||||
|
||||
/* helpers to use the available variant behind new API */
|
||||
static inline int compat_bpf_map_create(enum bpf_map_type map_type,
|
||||
@@ -47,10 +45,3 @@ static inline int compat_bpf_map_create(enum bpf_map_type map_type,
|
||||
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 */);
|
||||
}
|
||||
|
||||
static inline int compat_libbpf_probe_bpf_prog_type(enum bpf_prog_type prog_type, const void *opts) {
|
||||
if (sym_libbpf_probe_bpf_prog_type)
|
||||
return sym_libbpf_probe_bpf_prog_type(prog_type, opts);
|
||||
|
||||
return sym_bpf_probe_prog_type(prog_type, 0);
|
||||
}
|
||||
|
||||
+16
-17
@@ -51,12 +51,10 @@ 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 *);
|
||||
int (*sym_libbpf_probe_bpf_prog_type)(enum bpf_prog_type, const void *);
|
||||
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);
|
||||
bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
||||
|
||||
_printf_(2,0)
|
||||
static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) {
|
||||
@@ -72,10 +70,14 @@ static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_lis
|
||||
return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap);
|
||||
}
|
||||
|
||||
int dlopen_bpf(void) {
|
||||
int dlopen_bpf_full(int log_level) {
|
||||
static int cached = 0;
|
||||
void *dl;
|
||||
int r;
|
||||
|
||||
if (cached != 0)
|
||||
return cached;
|
||||
|
||||
ELF_NOTE_DLOPEN("bpf",
|
||||
"Support firewalling and sandboxing with BPF",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
@@ -91,8 +93,9 @@ int dlopen_bpf(void) {
|
||||
* list for both files, and when we assume 1.0+ is present we can remove this dlopen */
|
||||
dl = dlopen("libbpf.so.0", RTLD_NOW|RTLD_NODELETE);
|
||||
if (!dl)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"neither libbpf.so.1 nor libbpf.so.0 are installed: %s", dlerror());
|
||||
return cached = log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Neither libbpf.so.1 nor libbpf.so.0 are installed, cgroup BPF features disabled: %s",
|
||||
dlerror());
|
||||
|
||||
log_debug("Loaded 'libbpf.so.0' via dlopen()");
|
||||
|
||||
@@ -101,11 +104,9 @@ int dlopen_bpf(void) {
|
||||
dl, LOG_DEBUG,
|
||||
#if MODERN_LIBBPF
|
||||
/* Don't exist anymore in new libbpf, hence cannot type check them */
|
||||
DLSYM_ARG_FORCE(bpf_create_map),
|
||||
DLSYM_ARG_FORCE(bpf_probe_prog_type)
|
||||
DLSYM_ARG_FORCE(bpf_create_map)
|
||||
#else
|
||||
DLSYM_ARG(bpf_create_map),
|
||||
DLSYM_ARG(bpf_probe_prog_type)
|
||||
DLSYM_ARG(bpf_create_map)
|
||||
#endif
|
||||
);
|
||||
|
||||
@@ -118,18 +119,16 @@ int dlopen_bpf(void) {
|
||||
dl, LOG_DEBUG,
|
||||
#if MODERN_LIBBPF
|
||||
DLSYM_ARG(bpf_map_create),
|
||||
DLSYM_ARG(libbpf_probe_bpf_prog_type),
|
||||
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(libbpf_probe_bpf_prog_type),
|
||||
DLSYM_ARG_FORCE(bpf_object__next_map)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
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,
|
||||
@@ -171,14 +170,14 @@ int dlopen_bpf(void) {
|
||||
DLSYM_ARG(ring_buffer__new),
|
||||
DLSYM_ARG(ring_buffer__poll));
|
||||
if (r < 0)
|
||||
return r;
|
||||
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;
|
||||
|
||||
return r;
|
||||
return cached = true;
|
||||
}
|
||||
|
||||
int bpf_get_error_translated(const void *ptr) {
|
||||
@@ -200,8 +199,8 @@ int bpf_get_error_translated(const void *ptr) {
|
||||
|
||||
#else
|
||||
|
||||
int dlopen_bpf(void) {
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"libbpf support is not compiled in.");
|
||||
int dlopen_bpf_full(int log_level) {
|
||||
return log_once_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"libbpf support is not compiled in, cgroup BPF features disabled.");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#if HAVE_LIBBPF
|
||||
|
||||
#include <bpf/bpf.h>
|
||||
@@ -48,4 +51,7 @@ int bpf_get_error_translated(const void *ptr);
|
||||
|
||||
#endif
|
||||
|
||||
int dlopen_bpf(void);
|
||||
int dlopen_bpf_full(int log_level);
|
||||
static inline int dlopen_bpf(void) {
|
||||
return dlopen_bpf_full(LOG_DEBUG);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/bpf_insn.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@@ -42,6 +43,52 @@ DEFINE_STRING_TABLE_LOOKUP(bpf_cgroup_attach_type, int);
|
||||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(bpf_program_hash_ops, void, trivial_hash_func, trivial_compare_func, bpf_program_free);
|
||||
|
||||
int bpf_program_supported(void) {
|
||||
static int cached = 0;
|
||||
|
||||
if (cached != 0)
|
||||
return cached;
|
||||
|
||||
/* Currently, we only use the following three types:
|
||||
* - BPF_PROG_TYPE_CGROUP_SKB, supported since kernel v4.10 (0e33661de493db325435d565a4a722120ae4cbf3),
|
||||
* - BPF_PROG_TYPE_CGROUP_DEVICE, supported since kernel v4.15 (ebc614f687369f9df99828572b1d85a7c2de3d92),
|
||||
* - BPF_PROG_TYPE_CGROUP_SOCK_ADDR, supported since kernel v4.17 (4fbac77d2d092b475dda9eea66da674369665427).
|
||||
* Hence, as our baseline on the kernel is v5.4, it is not necessary to check if we can create BPF
|
||||
* programs of hthese types.
|
||||
*
|
||||
* However, unfortunately the kernel allows us to create BPF_PROG_TYPE_CGROUP_SKB (maybe also other types)
|
||||
* programs even when CONFIG_CGROUP_BPF is turned off at kernel compilation time. This sucks of course:
|
||||
* why does it allow us to create a cgroup BPF program if we can't do a thing with it later?
|
||||
*
|
||||
* We detect this case by issuing the BPF_PROG_DETACH bpf() call with invalid file descriptors: if
|
||||
* CONFIG_CGROUP_BPF is turned off, then the call will fail early with EINVAL. If it is turned on the
|
||||
* parameters are validated however, and that'll fail with EBADF then.
|
||||
*
|
||||
* The check seems also important when we are running with sanitizers. With sanitizers (at least with
|
||||
* LLVM v20), the following check and other bpf() calls fails even if the kernel supports BPF. To
|
||||
* avoid unexpected fail when running with sanitizers, let's explicitly check if bpf() syscall works. */
|
||||
|
||||
/* Clang and GCC (>=15) do not 0-pad with structured initialization, causing the kernel to reject the
|
||||
* bpf_attr as invalid. See: https://github.com/torvalds/linux/blob/v5.9/kernel/bpf/syscall.c#L65
|
||||
* Hence, we cannot use structured initialization here, and need to clear the structure with zero
|
||||
* explicitly before use. */
|
||||
union bpf_attr attr;
|
||||
zero(attr);
|
||||
attr.attach_type = BPF_CGROUP_INET_EGRESS; /* since kernel v4.10 (0e33661de493db325435d565a4a722120ae4cbf3) */
|
||||
attr.target_fd = -EBADF;
|
||||
attr.attach_bpf_fd = -EBADF;
|
||||
|
||||
if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) {
|
||||
if (errno == EBADF) /* YAY! */
|
||||
return cached = true;
|
||||
|
||||
return cached = log_debug_errno(errno, "Didn't get EBADF from invalid BPF_PROG_DETACH call: %m");
|
||||
}
|
||||
|
||||
return cached = log_debug_errno(SYNTHETIC_ERRNO(EBADE),
|
||||
"Wut? Kernel accepted our invalid BPF_PROG_DETACH call? Something is weird, assuming BPF is broken and hence not supported.");
|
||||
}
|
||||
|
||||
BPFProgram *bpf_program_free(BPFProgram *p) {
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
@@ -33,6 +33,8 @@ struct BPFProgram {
|
||||
uint32_t attached_flags;
|
||||
};
|
||||
|
||||
int bpf_program_supported(void);
|
||||
|
||||
int bpf_program_new(uint32_t prog_type, const char *prog_name, BPFProgram **ret);
|
||||
int bpf_program_new_from_bpffs_path(const char *path, BPFProgram **ret);
|
||||
BPFProgram *bpf_program_free(BPFProgram *p);
|
||||
|
||||
+4
-1
@@ -219,7 +219,10 @@ static int allocate_scope(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_bus_default_system(&bus);
|
||||
if (geteuid() == 0)
|
||||
r = sd_bus_default_system(&bus);
|
||||
else
|
||||
r = sd_bus_default_user(&bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to system bus: %m");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user