]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
libbpf: add compat helpers for libbpf down to 0.1.0 24511/head
authorDominique Martinet <asmadeus@codewreck.org>
Fri, 30 Sep 2022 10:25:18 +0000 (19:25 +0900)
committerDominique Martinet <asmadeus@codewreck.org>
Thu, 6 Oct 2022 12:33:55 +0000 (21:33 +0900)
- new symbols are available from libbpf 0.6.0 so could be used with
libbpf.so.0, but we're sure the old symbols will be there and this
simplifies code
- detection at runtime should always work, regardless of whether systemd
has been compiled with older or newer libbpf and runs with older or newer
libbpf

meson.build
src/core/bpf-lsm.c
src/core/bpf-socket-bind.c
src/core/restrict-ifaces.c
src/shared/bpf-compat.h [new file with mode: 0644]
src/shared/bpf-dlopen.c
src/shared/bpf-dlopen.h

index 0b5fdd17374dad03aba8d4a0bd075ffb2bffa0a5..b543a8376196d7cee226f8439b7ccfb3f6248c03 100644 (file)
@@ -1050,7 +1050,7 @@ want_bpf_framework = get_option('bpf-framework')
 bpf_compiler = get_option('bpf-compiler')
 bpf_framework_required = want_bpf_framework == 'true'
 
-libbpf_version_requirement = '>= 0.7.0'
+libbpf_version_requirement = '>= 0.1.0'
 if bpf_compiler == 'gcc'
         libbpf_version_requirement = '>= 1.0.0'
 endif
index 33c9322e7ed86553a746b504fa2a753affb3fe6e..173221b9f178eb1c0e981d5658fe74f422cc9373 100644 (file)
@@ -72,7 +72,7 @@ static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) {
                                        sym_bpf_map__name(obj->maps.cgroup_hash));
 
         /* Dummy map to satisfy the verifier */
-        inner_map_fd = sym_bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(uint32_t), sizeof(uint32_t), 128U, NULL);
+        inner_map_fd = compat_bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(uint32_t), sizeof(uint32_t), 128U, NULL);
         if (inner_map_fd < 0)
                 return log_error_errno(errno, "bpf-lsm: Failed to create BPF map: %m");
 
@@ -202,7 +202,7 @@ int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, bool allo
                 return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
                                             "bpf-lsm: BPF LSM object is not installed, has setup failed?");
 
-        int inner_map_fd = sym_bpf_map_create(
+        int inner_map_fd = compat_bpf_map_create(
                         BPF_MAP_TYPE_HASH,
                         NULL,
                         sizeof(uint32_t),
index 790813bdbe45133973075817b9d55b088dcb8054..660ffdb7232567f81c9b65e780a39684b97eefde 100644 (file)
@@ -120,7 +120,7 @@ int bpf_socket_bind_supported(void) {
         if (!cgroup_bpf_supported())
                 return false;
 
-        if (!sym_libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*opts=*/NULL)) {
+        if (!compat_libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*opts=*/NULL)) {
                 log_debug("bpf-socket-bind: BPF program type cgroup_sock_addr is not supported");
                 return false;
         }
index c0daa38a03f62e110393f826e7face60078dcd92..134f70a07b862fb8bf8b5ef6ea76683478e03488 100644 (file)
@@ -83,7 +83,7 @@ int restrict_network_interfaces_supported(void) {
         if (!cgroup_bpf_supported())
                 return (supported = false);
 
-        if (!sym_libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*opts=*/NULL)) {
+        if (!compat_libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*opts=*/NULL)) {
                 log_debug("restrict-interfaces: BPF program type cgroup_skb is not supported");
                 return (supported = false);
         }
diff --git a/src/shared/bpf-compat.h b/src/shared/bpf-compat.h
new file mode 100644 (file)
index 0000000..04ade82
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+/* 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 bool (*sym_libbpf_probe_bpf_prog_type)(enum bpf_prog_type, const void *);
+
+/* 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,
+                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 */);
+}
+
+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);
+}
index ad5432a94942e2be5ef9bfca944aa4683d7b053c..2556053cbb68bca02fdf17741bc33db7b361e5d1 100644 (file)
@@ -6,8 +6,6 @@
 #include "strv.h"
 
 #if HAVE_LIBBPF
-static void *bpf_dl = NULL;
-
 struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
 struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *);
 int (*sym_bpf_link__fd)(const struct bpf_link *);
@@ -29,6 +27,10 @@ const char* (*sym_bpf_program__name)(const struct bpf_program *);
 libbpf_print_fn_t (*sym_libbpf_set_print)(libbpf_print_fn_t);
 long (*sym_libbpf_get_error)(const void *);
 
+/* 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) {
 #if !LOG_TRACE
@@ -44,16 +46,37 @@ static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_lis
 }
 
 int dlopen_bpf(void) {
+        void *dl;
         int r;
 
-        FOREACH_STRING(f, "libbpf.so.1", "libbpf.so.0") {
-                r = dlopen_many_sym_or_warn(
-                        &bpf_dl, f, LOG_DEBUG,
+        dl = dlopen("libbpf.so.1", RTLD_LAZY);
+        if (!dl) {
+                /* 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 */
+                dl = dlopen("libbpf.so.0", RTLD_LAZY);
+                if (!dl)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                               "neither libbpf.so.1 nor libbpf.so.0 are installed: %s", dlerror());
+
+                /* symbols deprecated in 1.0 we use as compat */
+                r = dlsym_many_or_warn(dl, LOG_DEBUG,
+                                DLSYM_ARG(bpf_create_map),
+                                DLSYM_ARG(bpf_probe_prog_type));
+        } else {
+                /* symbols available from 0.7.0 */
+                r = dlsym_many_or_warn(dl, LOG_DEBUG,
+                                DLSYM_ARG(bpf_map_create),
+                                DLSYM_ARG(libbpf_probe_bpf_prog_type));
+        }
+
+        r = dlsym_many_or_warn(
+                        dl, LOG_DEBUG,
                         DLSYM_ARG(bpf_link__destroy),
                         DLSYM_ARG(bpf_link__fd),
                         DLSYM_ARG(bpf_map__fd),
                         DLSYM_ARG(bpf_map__name),
-                        DLSYM_ARG(bpf_map_create),
                         DLSYM_ARG(bpf_map__set_max_entries),
                         DLSYM_ARG(bpf_map_update_elem),
                         DLSYM_ARG(bpf_map_delete_elem),
@@ -66,12 +89,8 @@ int dlopen_bpf(void) {
                         DLSYM_ARG(bpf_program__attach_cgroup),
                         DLSYM_ARG(bpf_program__attach_lsm),
                         DLSYM_ARG(bpf_program__name),
-                        DLSYM_ARG(libbpf_probe_bpf_prog_type),
                         DLSYM_ARG(libbpf_set_print),
                         DLSYM_ARG(libbpf_get_error));
-                if (r >= 0)
-                        break;
-        }
         if (r < 0)
                 return r;
 
index 16b23ef6c511bdcde73dbf0adf067f6fd9cddf14..95951e63e0e4c61e7a593332e45380d817211dfd 100644 (file)
@@ -6,13 +6,14 @@
 #include <bpf/bpf.h>
 #include <bpf/libbpf.h>
 
+#include "bpf-compat.h"
+
 extern struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
 extern struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *);
 extern int (*sym_bpf_link__fd)(const struct bpf_link *);
 extern int (*sym_bpf_link__destroy)(struct bpf_link *);
 extern int (*sym_bpf_map__fd)(const struct bpf_map *);
 extern const char* (*sym_bpf_map__name)(const struct bpf_map *);
-extern int (*sym_bpf_map_create)(enum bpf_map_type,  const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *);
 extern int (*sym_bpf_map__set_max_entries)(struct bpf_map *, __u32);
 extern int (*sym_bpf_map_update_elem)(int, const void *, const void *, __u64);
 extern int (*sym_bpf_map_delete_elem)(int, const void *);
@@ -25,7 +26,6 @@ extern int (*sym_bpf_object__attach_skeleton)(struct bpf_object_skeleton *);
 extern void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *);
 extern void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *);
 extern const char* (*sym_bpf_program__name)(const struct bpf_program *);
-extern bool (*sym_libbpf_probe_bpf_prog_type)(enum bpf_prog_type, const void *);
 extern libbpf_print_fn_t (*sym_libbpf_set_print)(libbpf_print_fn_t);
 extern long (*sym_libbpf_get_error)(const void *);