diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-05-25 16:51:16 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-25 16:51:16 +0200 |
commit | 9caf9859b4608b88a38619d65d890ab6f2fcac43 (patch) | |
tree | e5aa9d60b31f3c90c625aaebc80fdbb73332dc8a /src | |
parent | 13eeefe1a8b65144294fc8777f4c96507f79da6b (diff) | |
parent | c5fd89adcde0b6e954000328471336ec8e7a0c69 (diff) | |
download | systemd-9caf9859b4608b88a38619d65d890ab6f2fcac43.tar.gz |
Merge pull request #19705 from bluca/bpf_dlopen
core: make libbpf a dlopen() dependency
Diffstat (limited to 'src')
-rw-r--r-- | src/core/meson.build | 2 | ||||
-rw-r--r-- | src/core/socket-bind.c | 39 | ||||
-rw-r--r-- | src/shared/bpf-dlopen.c | 73 | ||||
-rw-r--r-- | src/shared/bpf-dlopen.h | 29 | ||||
-rw-r--r-- | src/shared/bpf-link.c | 23 | ||||
-rw-r--r-- | src/shared/meson.build | 4 | ||||
-rw-r--r-- | src/test/meson.build | 2 | ||||
-rw-r--r-- | src/test/test-dlopen-so.c | 5 |
8 files changed, 152 insertions, 25 deletions
diff --git a/src/core/meson.build b/src/core/meson.build index e93d17a43a..69013311ea 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -159,7 +159,7 @@ libcore = static_library( include_directories : includes, dependencies : [versiondep, threads, - libbpf, + libdl, librt, libseccomp, libpam, diff --git a/src/core/socket-bind.c b/src/core/socket-bind.c index ed6c36c11f..b44e3ae8ab 100644 --- a/src/core/socket-bind.c +++ b/src/core/socket-bind.c @@ -9,6 +9,7 @@ #if BPF_FRAMEWORK /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */ +#include "bpf-dlopen.h" #include "bpf-link.h" #include "bpf/socket_bind/socket-bind.skel.h" #include "bpf/socket_bind/socket-bind-api.bpf.h" @@ -37,7 +38,7 @@ static int update_rules_map( .port_min = item->port_min, }; - if (bpf_map_update_elem(map_fd, &key, &val, BPF_ANY) != 0) + if (sym_bpf_map_update_elem(map_fd, &key, &val, BPF_ANY) != 0) return -errno; } @@ -71,34 +72,34 @@ static int prepare_socket_bind_bpf( if (!obj) return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOMEM), "Failed to open BPF object"); - if (bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0) + if (sym_bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0) return log_unit_error_errno(u, errno, - "Failed to resize BPF map '%s': %m", bpf_map__name(obj->maps.sd_bind_allow)); + "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow)); - if (bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0) + if (sym_bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0) return log_unit_error_errno(u, errno, - "Failed to resize BPF map '%s': %m", bpf_map__name(obj->maps.sd_bind_deny)); + "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny)); if (socket_bind_bpf__load(obj) != 0) return log_unit_error_errno(u, errno, "Failed to load BPF object"); - allow_map_fd = bpf_map__fd(obj->maps.sd_bind_allow); + allow_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_allow); assert(allow_map_fd >= 0); r = update_rules_map(allow_map_fd, allow); if (r < 0) return log_unit_error_errno( u, r, "Failed to put socket bind allow rules into BPF map '%s'", - bpf_map__name(obj->maps.sd_bind_allow)); + sym_bpf_map__name(obj->maps.sd_bind_allow)); - deny_map_fd = bpf_map__fd(obj->maps.sd_bind_deny); + deny_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_deny); assert(deny_map_fd >= 0); r = update_rules_map(deny_map_fd, deny); if (r < 0) return log_unit_error_errno( u, r, "Failed to put socket bind deny rules into BPF map '%s'", - bpf_map__name(obj->maps.sd_bind_deny)); + sym_bpf_map__name(obj->maps.sd_bind_deny)); *ret_obj = TAKE_PTR(obj); return 0; @@ -117,7 +118,13 @@ int socket_bind_supported(void) { return 0; } - if (!bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) { + r = dlopen_bpf(); + if (r < 0) { + log_info_errno(r, "Could not load libbpf: %m"); + return 0; + } + + if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) { log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF program type cgroup_sock_addr is not supported"); return 0; @@ -178,17 +185,17 @@ static int socket_bind_install_impl(Unit *u) { return log_unit_error_errno( u, errno, "Failed to open cgroup=%s for reading", cgroup_path); - ipv4 = bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd); - r = libbpf_get_error(ipv4); + ipv4 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd); + r = sym_libbpf_get_error(ipv4); if (r != 0) return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program", - bpf_program__name(obj->progs.sd_bind4)); + sym_bpf_program__name(obj->progs.sd_bind4)); - ipv6 = bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd); - r = libbpf_get_error(ipv6); + ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd); + r = sym_libbpf_get_error(ipv6); if (r != 0) return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program", - bpf_program__name(obj->progs.sd_bind6)); + sym_bpf_program__name(obj->progs.sd_bind6)); u->ipv4_socket_bind_link = TAKE_PTR(ipv4); u->ipv6_socket_bind_link = TAKE_PTR(ipv6); diff --git a/src/shared/bpf-dlopen.c b/src/shared/bpf-dlopen.c new file mode 100644 index 0000000000..64120f17c5 --- /dev/null +++ b/src/shared/bpf-dlopen.c @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "dlfcn-util.h" +#include "bpf-dlopen.h" + +#if HAVE_LIBBPF +static void *bpf_dl = NULL; + +struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int); +long (*sym_libbpf_get_error)(const void *); +int (*sym_bpf_link__fd)(const struct bpf_link *); +int (*sym_bpf_link__destroy)(struct bpf_link *); +int (*sym_bpf_map__fd)(const struct bpf_map *); +const char* (*sym_bpf_map__name)(const struct bpf_map *); +int (*sym_bpf_map__resize)(struct bpf_map *, __u32); +int (*sym_bpf_map_update_elem)(int, const void *, const void *, __u64); +int (*sym_bpf_object__open_skeleton)(struct bpf_object_skeleton *, const struct bpf_object_open_opts *); +int (*sym_bpf_object__load_skeleton)(struct bpf_object_skeleton *); +int (*sym_bpf_object__attach_skeleton)(struct bpf_object_skeleton *); +void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *); +void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *); +bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32); +const char* (*sym_bpf_program__name)(const struct bpf_program *); + +int dlopen_bpf(void) { + _cleanup_(dlclosep) void *dl = NULL; + int r; + + if (bpf_dl) + return 0; /* Already loaded */ + + dl = dlopen("libbpf.so.0", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "libbpf is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_ERR, + DLSYM_ARG(bpf_link__destroy), + DLSYM_ARG(bpf_link__fd), + DLSYM_ARG(bpf_map__fd), + DLSYM_ARG(bpf_map__name), + DLSYM_ARG(bpf_map__resize), + DLSYM_ARG(bpf_map_update_elem), + DLSYM_ARG(bpf_object__open_skeleton), + DLSYM_ARG(bpf_object__load_skeleton), + DLSYM_ARG(bpf_object__attach_skeleton), + DLSYM_ARG(bpf_object__detach_skeleton), + DLSYM_ARG(bpf_object__destroy_skeleton), + DLSYM_ARG(bpf_probe_prog_type), + DLSYM_ARG(bpf_program__attach_cgroup), + DLSYM_ARG(bpf_program__name), + DLSYM_ARG(libbpf_get_error), + NULL); + if (r < 0) + return r; + + /* Note that we never release the reference here, because there's no real reason to, after all this + * was traditionally a regular shared library dependency which lives forever too. */ + bpf_dl = TAKE_PTR(dl); + + return 1; +} + +#else + +int dlopen_bpf(void) { + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "libbpf support is not compiled in."); +} +#endif diff --git a/src/shared/bpf-dlopen.h b/src/shared/bpf-dlopen.h new file mode 100644 index 0000000000..fbb5531aff --- /dev/null +++ b/src/shared/bpf-dlopen.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#if HAVE_LIBBPF + +#include <bpf/bpf.h> +#include <bpf/libbpf.h> + +extern struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int); +extern long (*sym_libbpf_get_error)(const void *); +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__resize)(struct bpf_map *, __u32); +extern int (*sym_bpf_map_update_elem)(int, const void *, const void *, __u64); +/* The *_skeleton APIs are autogenerated by bpftool, the targets can be found + * in ./build/src/core/bpf/socket_bind/socket-bind.skel.h */ +extern int (*sym_bpf_object__open_skeleton)(struct bpf_object_skeleton *, const struct bpf_object_open_opts *); +extern int (*sym_bpf_object__load_skeleton)(struct bpf_object_skeleton *); +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 bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32); +extern const char* (*sym_bpf_program__name)(const struct bpf_program *); + +#endif + +int dlopen_bpf(void); diff --git a/src/shared/bpf-link.c b/src/shared/bpf-link.c index f718cb7d2d..405874374c 100644 --- a/src/shared/bpf-link.c +++ b/src/shared/bpf-link.c @@ -1,18 +1,26 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include "bpf-dlopen.h" #include "bpf-link.h" #include "serialize.h" bool can_link_bpf_program(struct bpf_program *prog) { _cleanup_(bpf_link_freep) struct bpf_link *link = NULL; + int r; assert(prog); + r = dlopen_bpf(); + if (r < 0) { + log_debug_errno(r, "Could not load libbpf: %m"); + return false; + } + /* Pass invalid cgroup fd intentionally. */ - link = bpf_program__attach_cgroup(prog, /*cgroup_fd=*/-1); + link = sym_bpf_program__attach_cgroup(prog, /*cgroup_fd=*/-1); /* EBADF indicates that bpf_link is supported by kernel. */ - return libbpf_get_error(link) == -EBADF; + return sym_libbpf_get_error(link) == -EBADF; } int serialize_bpf_link(FILE *f, FDSet *fds, const char *key, struct bpf_link *link) { @@ -23,16 +31,19 @@ int serialize_bpf_link(FILE *f, FDSet *fds, const char *key, struct bpf_link *li if (!link) return -ENOENT; - if (libbpf_get_error(link) != 0) + if (sym_libbpf_get_error(link) != 0) return -EINVAL; - fd = bpf_link__fd(link); + fd = sym_bpf_link__fd(link); return serialize_fd(f, fds, key, fd); } struct bpf_link *bpf_link_free(struct bpf_link *link) { - /* bpf_link__destroy handles link == NULL case */ - (void) bpf_link__destroy(link); + /* Avoid a useless dlopen() if link == NULL */ + if (!link) + return NULL; + + (void) sym_bpf_link__destroy(link); return NULL; } diff --git a/src/shared/meson.build b/src/shared/meson.build index 2e7132c402..6ecdf576ab 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -23,6 +23,8 @@ shared_sources = files(''' boot-timestamps.h bootspec.c bootspec.h + bpf-dlopen.c + bpf-dlopen.h bpf-program.c bpf-program.h bridge-util.c @@ -387,9 +389,9 @@ libshared_name = 'systemd-shared-@0@'.format(meson.project_version()) libshared_deps = [threads, libacl, libblkid, - libbpf, libcap, libcrypt, + libdl, libgcrypt, libiptc, libkmod, diff --git a/src/test/meson.build b/src/test/meson.build index 9b11324c7b..e02eaf78ff 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -616,7 +616,7 @@ tests += [ [['src/test/test-socket-bind.c'], [libcore, libshared], - [libbpf], + [libdl], core_includes, 'BPF_FRAMEWORK'], ] diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index 8e1ce6a0d0..ea2ef31b1f 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -3,6 +3,7 @@ #include <dlfcn.h> #include <stdlib.h> +#include "bpf-dlopen.h" #include "cryptsetup-util.h" #include "idn-util.h" #include "libfido2-util.h" @@ -44,6 +45,10 @@ static int run(int argc, char **argv) { assert_se(dlopen_libfido2() >= 0); #endif +#if HAVE_LIBBPF + assert_se(dlopen_bpf() >= 0); +#endif + return 0; } |