mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-10 01:17:44 +03:00
core: make libbpf a dlopen() dependency
This commit is contained in:
parent
936cfad7e5
commit
c5fd89adcd
@ -1675,7 +1675,7 @@ install_libsystemd_static = static_library(
|
|||||||
libxz,
|
libxz,
|
||||||
libzstd,
|
libzstd,
|
||||||
liblz4,
|
liblz4,
|
||||||
libbpf,
|
libdl,
|
||||||
libcap,
|
libcap,
|
||||||
libblkid,
|
libblkid,
|
||||||
libmount,
|
libmount,
|
||||||
|
@ -159,7 +159,7 @@ libcore = static_library(
|
|||||||
include_directories : includes,
|
include_directories : includes,
|
||||||
dependencies : [versiondep,
|
dependencies : [versiondep,
|
||||||
threads,
|
threads,
|
||||||
libbpf,
|
libdl,
|
||||||
librt,
|
librt,
|
||||||
libseccomp,
|
libseccomp,
|
||||||
libpam,
|
libpam,
|
||||||
|
@ -9,6 +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-link.h"
|
#include "bpf-link.h"
|
||||||
#include "bpf/socket_bind/socket-bind.skel.h"
|
#include "bpf/socket_bind/socket-bind.skel.h"
|
||||||
#include "bpf/socket_bind/socket-bind-api.bpf.h"
|
#include "bpf/socket_bind/socket-bind-api.bpf.h"
|
||||||
@ -37,7 +38,7 @@ static int update_rules_map(
|
|||||||
.port_min = item->port_min,
|
.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;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,34 +72,34 @@ static int prepare_socket_bind_bpf(
|
|||||||
if (!obj)
|
if (!obj)
|
||||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOMEM), "Failed to open BPF object");
|
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,
|
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,
|
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)
|
if (socket_bind_bpf__load(obj) != 0)
|
||||||
return log_unit_error_errno(u, errno, "Failed to load BPF object");
|
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);
|
assert(allow_map_fd >= 0);
|
||||||
|
|
||||||
r = update_rules_map(allow_map_fd, allow);
|
r = update_rules_map(allow_map_fd, allow);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(
|
return log_unit_error_errno(
|
||||||
u, r, "Failed to put socket bind allow rules into BPF map '%s'",
|
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);
|
assert(deny_map_fd >= 0);
|
||||||
|
|
||||||
r = update_rules_map(deny_map_fd, deny);
|
r = update_rules_map(deny_map_fd, deny);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(
|
return log_unit_error_errno(
|
||||||
u, r, "Failed to put socket bind deny rules into BPF map '%s'",
|
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);
|
*ret_obj = TAKE_PTR(obj);
|
||||||
return 0;
|
return 0;
|
||||||
@ -117,7 +118,13 @@ int socket_bind_supported(void) {
|
|||||||
return 0;
|
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),
|
log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"BPF program type cgroup_sock_addr is not supported");
|
"BPF program type cgroup_sock_addr is not supported");
|
||||||
return 0;
|
return 0;
|
||||||
@ -178,17 +185,17 @@ static int socket_bind_install_impl(Unit *u) {
|
|||||||
return log_unit_error_errno(
|
return log_unit_error_errno(
|
||||||
u, errno, "Failed to open cgroup=%s for reading", cgroup_path);
|
u, errno, "Failed to open cgroup=%s for reading", cgroup_path);
|
||||||
|
|
||||||
ipv4 = bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd);
|
ipv4 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd);
|
||||||
r = libbpf_get_error(ipv4);
|
r = sym_libbpf_get_error(ipv4);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program",
|
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);
|
ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd);
|
||||||
r = libbpf_get_error(ipv6);
|
r = sym_libbpf_get_error(ipv6);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program",
|
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->ipv4_socket_bind_link = TAKE_PTR(ipv4);
|
||||||
u->ipv6_socket_bind_link = TAKE_PTR(ipv6);
|
u->ipv6_socket_bind_link = TAKE_PTR(ipv6);
|
||||||
|
73
src/shared/bpf-dlopen.c
Normal file
73
src/shared/bpf-dlopen.c
Normal file
@ -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
|
29
src/shared/bpf-dlopen.h
Normal file
29
src/shared/bpf-dlopen.h
Normal file
@ -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);
|
@ -1,18 +1,26 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
|
||||||
|
#include "bpf-dlopen.h"
|
||||||
#include "bpf-link.h"
|
#include "bpf-link.h"
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
|
|
||||||
bool can_link_bpf_program(struct bpf_program *prog) {
|
bool can_link_bpf_program(struct bpf_program *prog) {
|
||||||
_cleanup_(bpf_link_freep) struct bpf_link *link = NULL;
|
_cleanup_(bpf_link_freep) struct bpf_link *link = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(prog);
|
assert(prog);
|
||||||
|
|
||||||
|
r = dlopen_bpf();
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Could not load libbpf: %m");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Pass invalid cgroup fd intentionally. */
|
/* 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. */
|
/* 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) {
|
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)
|
if (!link)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
if (libbpf_get_error(link) != 0)
|
if (sym_libbpf_get_error(link) != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
fd = bpf_link__fd(link);
|
fd = sym_bpf_link__fd(link);
|
||||||
return serialize_fd(f, fds, key, fd);
|
return serialize_fd(f, fds, key, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bpf_link *bpf_link_free(struct bpf_link *link) {
|
struct bpf_link *bpf_link_free(struct bpf_link *link) {
|
||||||
/* bpf_link__destroy handles link == NULL case */
|
/* Avoid a useless dlopen() if link == NULL */
|
||||||
(void) bpf_link__destroy(link);
|
if (!link)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
(void) sym_bpf_link__destroy(link);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ shared_sources = files('''
|
|||||||
boot-timestamps.h
|
boot-timestamps.h
|
||||||
bootspec.c
|
bootspec.c
|
||||||
bootspec.h
|
bootspec.h
|
||||||
|
bpf-dlopen.c
|
||||||
|
bpf-dlopen.h
|
||||||
bpf-program.c
|
bpf-program.c
|
||||||
bpf-program.h
|
bpf-program.h
|
||||||
bridge-util.c
|
bridge-util.c
|
||||||
@ -387,9 +389,9 @@ libshared_name = 'systemd-shared-@0@'.format(meson.project_version())
|
|||||||
libshared_deps = [threads,
|
libshared_deps = [threads,
|
||||||
libacl,
|
libacl,
|
||||||
libblkid,
|
libblkid,
|
||||||
libbpf,
|
|
||||||
libcap,
|
libcap,
|
||||||
libcrypt,
|
libcrypt,
|
||||||
|
libdl,
|
||||||
libgcrypt,
|
libgcrypt,
|
||||||
libiptc,
|
libiptc,
|
||||||
libkmod,
|
libkmod,
|
||||||
|
@ -616,7 +616,7 @@ tests += [
|
|||||||
[['src/test/test-socket-bind.c'],
|
[['src/test/test-socket-bind.c'],
|
||||||
[libcore,
|
[libcore,
|
||||||
libshared],
|
libshared],
|
||||||
[libbpf],
|
[libdl],
|
||||||
core_includes,
|
core_includes,
|
||||||
'BPF_FRAMEWORK'],
|
'BPF_FRAMEWORK'],
|
||||||
]
|
]
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "bpf-dlopen.h"
|
||||||
#include "cryptsetup-util.h"
|
#include "cryptsetup-util.h"
|
||||||
#include "idn-util.h"
|
#include "idn-util.h"
|
||||||
#include "libfido2-util.h"
|
#include "libfido2-util.h"
|
||||||
@ -44,6 +45,10 @@ static int run(int argc, char **argv) {
|
|||||||
assert_se(dlopen_libfido2() >= 0);
|
assert_se(dlopen_libfido2() >= 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_LIBBPF
|
||||||
|
assert_se(dlopen_bpf() >= 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,7 +964,7 @@ install_missing_libraries() {
|
|||||||
local lib path
|
local lib path
|
||||||
# A number of dependencies is now optional via dlopen, so the install
|
# A number of dependencies is now optional via dlopen, so the install
|
||||||
# script will not pick them up, since it looks at linkage.
|
# script will not pick them up, since it looks at linkage.
|
||||||
for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2; do
|
for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2 libbpf; do
|
||||||
ddebug "Searching for $lib via pkg-config"
|
ddebug "Searching for $lib via pkg-config"
|
||||||
if pkg-config --exists "$lib"; then
|
if pkg-config --exists "$lib"; then
|
||||||
path="$(pkg-config --variable=libdir "$lib")"
|
path="$(pkg-config --variable=libdir "$lib")"
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -59,7 +60,11 @@ def gen_bpf_skeleton(bpftool_exec, in_file, out_fd):
|
|||||||
|
|
||||||
logging.debug('Generating BPF skeleton:')
|
logging.debug('Generating BPF skeleton:')
|
||||||
logging.debug('{}'.format(' '.join(bpftool_args)))
|
logging.debug('{}'.format(' '.join(bpftool_args)))
|
||||||
subprocess.check_call(bpftool_args, stdout=out_fd)
|
skel = subprocess.check_output(bpftool_args, universal_newlines=True)
|
||||||
|
# libbpf is used via dlopen(), so rename symbols as defined
|
||||||
|
# in src/shared/bpf-dlopen.h
|
||||||
|
skel = re.sub(r'(bpf_object__\w+_skeleton)', r'sym_\1', skel)
|
||||||
|
out_fd.write(skel)
|
||||||
|
|
||||||
|
|
||||||
def bpf_build(args):
|
def bpf_build(args):
|
||||||
|
Loading…
Reference in New Issue
Block a user