]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/bpf-socket-bind.c
core: split out cgroup specific state fields from Unit → CGroupRuntime
[thirdparty/systemd.git] / src / core / bpf-socket-bind.c
index 66c82d54699753a7396fd6da2d0c49da863dc6ca..465216a7d0dfd29708ffe42b5d4d1f481fa6ac15 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #if BPF_FRAMEWORK
 #include <bpf/bpf.h>
@@ -11,8 +11,9 @@
 /* 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-util.h"
 #include "bpf/socket_bind/socket-bind-api.bpf.h"
+#include "bpf/socket_bind/socket-bind-skel.h"
 
 static struct socket_bind_bpf *socket_bind_bpf_free(struct socket_bind_bpf *obj) {
         /* socket_bind_bpf__destroy handles object == NULL case */
@@ -27,7 +28,6 @@ static int update_rules_map(
                 int map_fd,
                 CGroupSocketBindItem *head) {
 
-        CGroupSocketBindItem *item;
         uint32_t i = 0;
 
         assert(map_fd >= 0);
@@ -35,6 +35,7 @@ static int update_rules_map(
         LIST_FOREACH(socket_bind_items, item, head) {
                 struct socket_bind_rule val = {
                         .address_family = (uint32_t) item->address_family,
+                        .protocol = item->ip_protocol,
                         .nr_ports = item->nr_ports,
                         .port_min = item->port_min,
                 };
@@ -57,7 +58,6 @@ static int prepare_socket_bind_bpf(
         _cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
         size_t allow_count = 0, deny_count = 0;
         int allow_map_fd, deny_map_fd, r;
-        CGroupSocketBindItem *item;
 
         assert(ret_obj);
 
@@ -69,28 +69,27 @@ static int prepare_socket_bind_bpf(
 
         if (allow_count > SOCKET_BIND_MAX_RULES)
                 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
-                                           "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
+                                           "bpf-socket-bind: Maximum number of socket bind rules=%i is exceeded", SOCKET_BIND_MAX_RULES);
 
         if (deny_count > SOCKET_BIND_MAX_RULES)
                 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
-                                           "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
+                                           "bpf-socket-bind: Maximum number of socket bind rules=%i is exceeded", SOCKET_BIND_MAX_RULES);
 
         obj = socket_bind_bpf__open();
         if (!obj)
-                return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, SYNTHETIC_ERRNO(ENOMEM),
-                                           "Failed to open BPF object");
+                return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "bpf-socket-bind: Failed to open BPF object: %m");
 
-        if (sym_bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0)
+        if (sym_bpf_map__set_max_entries(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0)
                 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
-                                           "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow));
+                                           "bpf-socket-bind: Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow));
 
-        if (sym_bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0)
+        if (sym_bpf_map__set_max_entries(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0)
                 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
-                                           "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny));
+                                           "bpf-socket-bind: 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_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno,
-                                           "Failed to load BPF object: %m");
+                                           "bpf-socket-bind: Failed to load BPF object: %m");
 
         allow_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_allow);
         assert(allow_map_fd >= 0);
@@ -98,7 +97,7 @@ static int prepare_socket_bind_bpf(
         r = update_rules_map(allow_map_fd, allow);
         if (r < 0)
                 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
-                                           "Failed to put socket bind allow rules into BPF map '%s'",
+                                           "bpf-socket-bind: Failed to put socket bind allow rules into BPF map '%s'",
                                            sym_bpf_map__name(obj->maps.sd_bind_allow));
 
         deny_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_deny);
@@ -107,7 +106,7 @@ static int prepare_socket_bind_bpf(
         r = update_rules_map(deny_map_fd, deny);
         if (r < 0)
                 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
-                                           "Failed to put socket bind deny rules into BPF map '%s'",
+                                           "bpf-socket-bind: Failed to put socket bind deny rules into BPF map '%s'",
                                            sym_bpf_map__name(obj->maps.sd_bind_deny));
 
         *ret_obj = TAKE_PTR(obj);
@@ -118,25 +117,17 @@ int bpf_socket_bind_supported(void) {
         _cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
         int r;
 
-        r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
-        if (r < 0)
-                return log_debug_errno(r, "Can't determine whether the unified hierarchy is used: %m");
-        if (r == 0) {
-                log_debug("Not running with unified cgroup hierarchy, BPF is not supported");
-                return false;
-        }
-
-        if (dlopen_bpf() < 0)
+        if (!cgroup_bpf_supported())
                 return false;
 
-        if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) {
-                log_debug("BPF program type cgroup_sock_addr is not supported");
+        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;
         }
 
         r = prepare_socket_bind_bpf(/*unit=*/NULL, /*allow_rules=*/NULL, /*deny_rules=*/NULL, &obj);
         if (r < 0) {
-                log_debug_errno(r, "BPF based socket_bind is not supported: %m");
+                log_debug_errno(r, "bpf-socket-bind: socket bind filtering is not supported: %m");
                 return false;
         }
 
@@ -148,15 +139,20 @@ int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) {
 
         assert(u);
 
-        if (!u->initial_socket_bind_link_fds) {
-                u->initial_socket_bind_link_fds = fdset_new();
-                if (!u->initial_socket_bind_link_fds)
+        CGroupRuntime *crt = unit_get_cgroup_runtime(u);
+        if (!crt)
+                return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
+                                            "Failed to get control group runtime object.");
+
+        if (!crt->initial_socket_bind_link_fds) {
+                crt->initial_socket_bind_link_fds = fdset_new();
+                if (!crt->initial_socket_bind_link_fds)
                         return log_oom();
         }
 
-        r = fdset_put(u->initial_socket_bind_link_fds, fd);
+        r = fdset_put(crt->initial_socket_bind_link_fds, fd);
         if (r < 0)
-                return log_unit_error_errno(u, r, "Failed to put socket-bind BPF link fd %d to initial fdset", fd);
+                return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to put BPF fd %d to initial fdset", fd);
 
         return 0;
 }
@@ -165,8 +161,9 @@ static int socket_bind_install_impl(Unit *u) {
         _cleanup_(bpf_link_freep) struct bpf_link *ipv4 = NULL, *ipv6 = NULL;
         _cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
         _cleanup_free_ char *cgroup_path = NULL;
-        _cleanup_close_ int cgroup_fd = -1;
+        _cleanup_close_ int cgroup_fd = -EBADF;
         CGroupContext *cc;
+        CGroupRuntime *crt;
         int r;
 
         assert(u);
@@ -175,62 +172,73 @@ static int socket_bind_install_impl(Unit *u) {
         if (!cc)
                 return 0;
 
-        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
+        crt = unit_get_cgroup_runtime(u);
+        if (!crt)
+                return 0;
+
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, crt->cgroup_path, NULL, &cgroup_path);
         if (r < 0)
-                return log_unit_error_errno(u, r, "Failed to get cgroup path: %m");
+                return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to get cgroup path: %m");
 
         if (!cc->socket_bind_allow && !cc->socket_bind_deny)
                 return 0;
 
         r = prepare_socket_bind_bpf(u, cc->socket_bind_allow, cc->socket_bind_deny, &obj);
         if (r < 0)
-                return log_unit_error_errno(u, r, "Failed to load BPF object: %m");
+                return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to load BPF object: %m");
 
         cgroup_fd = open(cgroup_path, O_RDONLY | O_CLOEXEC, 0);
         if (cgroup_fd < 0)
-                return log_unit_error_errno(u, errno, "Failed to open cgroup=%s for reading: %m", cgroup_path);
+                return log_unit_error_errno(u, errno, "bpf-socket-bind: Failed to open cgroup %s for reading: %m", cgroup_path);
 
         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: %m",
+                return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to link '%s' cgroup-bpf program: %m",
                                             sym_bpf_program__name(obj->progs.sd_bind4));
 
         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: %m",
+                return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to link '%s' cgroup-bpf program: %m",
                                             sym_bpf_program__name(obj->progs.sd_bind6));
 
-        u->ipv4_socket_bind_link = TAKE_PTR(ipv4);
-        u->ipv6_socket_bind_link = TAKE_PTR(ipv6);
+        crt->ipv4_socket_bind_link = TAKE_PTR(ipv4);
+        crt->ipv6_socket_bind_link = TAKE_PTR(ipv6);
 
         return 0;
 }
 
 int bpf_socket_bind_install(Unit *u) {
+        CGroupRuntime *crt;
         int r;
 
         assert(u);
 
-        r = socket_bind_install_impl(u);
-        if (r == -ENOMEM)
-                return r;
+        crt = unit_get_cgroup_runtime(u);
+        if (!crt)
+                return 0;
 
-        fdset_close(u->initial_socket_bind_link_fds);
+        r = socket_bind_install_impl(u);
+        fdset_close(crt->initial_socket_bind_link_fds);
         return r;
 }
 
-int bpf_serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
+int bpf_socket_bind_serialize(Unit *u, FILE *f, FDSet *fds) {
+        CGroupRuntime *crt;
         int r;
 
         assert(u);
 
-        r = bpf_serialize_link(f, fds, "ipv4-socket-bind-bpf-link", u->ipv4_socket_bind_link);
+        crt = unit_get_cgroup_runtime(u);
+        if (!crt)
+                return 0;
+
+        r = bpf_serialize_link(f, fds, "ipv4-socket-bind-bpf-link", crt->ipv4_socket_bind_link);
         if (r < 0)
                 return r;
 
-        return bpf_serialize_link(f, fds, "ipv6-socket-bind-bpf-link", u->ipv6_socket_bind_link);
+        return bpf_serialize_link(f, fds, "ipv6-socket-bind-bpf-link", crt->ipv6_socket_bind_link);
 }
 
 #else /* ! BPF_FRAMEWORK */
@@ -243,10 +251,11 @@ int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) {
 }
 
 int bpf_socket_bind_install(Unit *u) {
-        return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to install socket bind: BPF framework is not supported");
+        return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                    "bpf-socket-bind: Failed to install; BPF framework is not supported");
 }
 
-int bpf_serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
+int bpf_socket_bind_serialize(Unit *u, FILE *f, FDSet *fds) {
         return 0;
 }
 #endif