]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared, bpf: add bpf link serialization
authorJulia Kartseva <hex@fb.com>
Mon, 19 Apr 2021 20:27:07 +0000 (13:27 -0700)
committerJulia Kartseva <hex@fb.com>
Mon, 26 Apr 2021 23:26:24 +0000 (16:26 -0700)
core: serialize socket_bind bpf links

src/core/socket-bind.c
src/core/socket-bind.h
src/core/unit-serialize.c
src/core/unit.c
src/core/unit.h
src/shared/bpf-link.c
src/shared/bpf-link.h

index f03bed5888fc2f3c7582393594608ee7c0fe914f..ed6c36c11f7281a58a6a81ca9a1fac0ba198cc0c 100644 (file)
@@ -132,7 +132,25 @@ int socket_bind_supported(void) {
         return can_link_bpf_program(obj->progs.sd_bind4);
 }
 
-int socket_bind_install(Unit *u) {
+int socket_bind_add_initial_link_fd(Unit *u, int fd) {
+        int r;
+
+        assert(u);
+
+        if (!u->initial_socket_bind_link_fds) {
+                u->initial_socket_bind_link_fds = fdset_new();
+                if (!u->initial_socket_bind_link_fds)
+                        return log_oom();
+        }
+
+        r = fdset_put(u->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 0;
+}
+
+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;
@@ -177,14 +195,44 @@ int socket_bind_install(Unit *u) {
 
         return 0;
 }
+
+int socket_bind_install(Unit *u) {
+        int r = socket_bind_install_impl(u);
+        if (r == -ENOMEM)
+                return r;
+
+        fdset_close(u->initial_socket_bind_link_fds);
+
+        return r;
+}
+
+int serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
+        int r;
+
+        assert(u);
+
+        r = serialize_bpf_link(f, fds, "ipv4-socket-bind-bpf-link", u->ipv4_socket_bind_link);
+        if (r < 0)
+                return r;
+
+        return serialize_bpf_link(f, fds, "ipv6-socket-bind-bpf-link", u->ipv6_socket_bind_link);
+}
+
 #else /* ! BPF_FRAMEWORK */
 int socket_bind_supported(void) {
         return 0;
 }
 
+int socket_bind_add_initial_link_fd(Unit *u, int fd) {
+        return 0;
+}
+
 int socket_bind_install(Unit *u) {
         log_unit_debug(u, "Failed to install socket bind: BPF framework is not supported");
         return 0;
 }
 
+int serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
+        return 0;
+}
 #endif
index 58b73579accffbf372e1a475280e19bff57040c0..2a6e71a9b91cf3366af743a2510f6a68aa5c03aa 100644 (file)
@@ -1,8 +1,15 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include "fdset.h"
 #include "unit.h"
 
 int socket_bind_supported(void);
 
+/* Add BPF link fd created before daemon-reload or daemon-reexec.
+ * FDs will be closed at the end of socket_bind_install. */
+int socket_bind_add_initial_link_fd(Unit *u, int fd);
+
 int socket_bind_install(Unit *u);
+
+int serialize_socket_bind(Unit *u, FILE *f, FDSet *fds);
index 3f099248ce680e7d9d2e7251d9703bc3c8fbbe3a..509210ad5e228eecca7809d663cbae7390ae07d6 100644 (file)
@@ -7,6 +7,7 @@
 #include "format-util.h"
 #include "parse-util.h"
 #include "serialize.h"
+#include "socket-bind.h"
 #include "string-table.h"
 #include "unit-serialize.h"
 #include "user-util.h"
@@ -151,6 +152,8 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         (void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
         (void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
 
+        (void) serialize_socket_bind(u, f, fds);
+
         if (uid_is_valid(u->ref_uid))
                 (void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
         if (gid_is_valid(u->ref_gid))
@@ -362,6 +365,23 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                 else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-invalidated-mask", l, v, cg_mask_from_string, u->cgroup_invalidated_mask))
                         continue;
 
+                else if (STR_IN_SET(l, "ipv4-socket-bind-bpf-link-fd", "ipv6-socket-bind-bpf-link-fd")) {
+                        int fd;
+
+                        if (safe_atoi(v, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                                log_unit_debug(u, "Failed to parse %s value: %s, ignoring.", l, v);
+                        else {
+                                if (fdset_remove(fds, fd) < 0) {
+                                        log_unit_debug(u, "Failed to remove %s value=%d from fdset", l, fd);
+
+                                        continue;
+                                }
+
+                                (void) socket_bind_add_initial_link_fd(u, fd);
+                        }
+                        continue;
+                }
+
                 else if (streq(l, "ref-uid")) {
                         uid_t uid;
 
index e8c06314297b743bfc622083c2d091658f1d29e1..6ef90eea0e41d5dcb8e1663b7f0eeeea51498862 100644 (file)
@@ -667,6 +667,8 @@ Unit* unit_free(Unit *u) {
         if (u->on_console)
                 manager_unref_console(u->manager);
 
+
+        fdset_free(u->initial_socket_bind_link_fds);
 #if BPF_FRAMEWORK
         bpf_link_free(u->ipv4_socket_bind_link);
         bpf_link_free(u->ipv6_socket_bind_link);
index a124376b785a89189926af7355c9cf7083fda5a8..5bc1237ce075585427234a078b5f601d2cf7609e 100644 (file)
@@ -309,6 +309,7 @@ typedef struct Unit {
          * attached to unit cgroup by provided program fd and attach type. */
         Hashmap *bpf_foreign_by_key;
 
+        FDSet *initial_socket_bind_link_fds;
 #if BPF_FRAMEWORK
         /* BPF links to BPF programs attached to cgroup/bind{4|6} hooks and
          * responsible for allowing or denying a unit to bind(2) to a socket
index 94d1a8c7ac5bb81614bfa9e3d547341e4f45bda6..f718cb7d2d39954f463dbd621a161e24da12d644 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #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;
@@ -14,6 +15,21 @@ bool can_link_bpf_program(struct bpf_program *prog) {
         return libbpf_get_error(link) == -EBADF;
 }
 
+int serialize_bpf_link(FILE *f, FDSet *fds, const char *key, struct bpf_link *link) {
+        int fd;
+
+        assert(key);
+
+        if (!link)
+                return -ENOENT;
+
+        if (libbpf_get_error(link) != 0)
+                return -EINVAL;
+
+        fd = 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);
index 7d529ad2cd1368bb4cdadd013c71c13f47ba5f72..095465b07ce98f77b3c33f2fa5ed786fde3d8f2a 100644 (file)
@@ -3,10 +3,14 @@
 #pragma once
 
 #include <bpf/libbpf.h>
+#include <stdio.h>
 
+#include "fdset.h"
 #include "macro.h"
 
 bool can_link_bpf_program(struct bpf_program *prog);
 
+int serialize_bpf_link(FILE *f, FDSet *fds, const char *key, struct bpf_link *link);
+
 struct bpf_link *bpf_link_free(struct bpf_link *p);
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct bpf_link *, bpf_link_free);