diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-06-08 18:20:02 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-06-08 22:02:35 +0200 |
commit | b57d75232615f98aefcf41cb145ec2ea3262857d (patch) | |
tree | 0aee580b48cc3ade4e039cdf8c825337f02383b8 /src/shared/bpf-program.c | |
parent | 7a7cf83dc3378d4063c728ff6a486c5edfe2f86c (diff) | |
download | systemd-b57d75232615f98aefcf41cb145ec2ea3262857d.tar.gz |
bpf-program: serialize attached BPF programs across daemon reexec/reload
Alternative to #17495
Diffstat (limited to 'src/shared/bpf-program.c')
-rw-r--r-- | src/shared/bpf-program.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/shared/bpf-program.c b/src/shared/bpf-program.c index 647dd6e2ba..0f865a7168 100644 --- a/src/shared/bpf-program.c +++ b/src/shared/bpf-program.c @@ -7,10 +7,12 @@ #include "alloc-util.h" #include "bpf-program.h" +#include "escape.h" #include "fd-util.h" #include "memory-util.h" #include "missing_syscall.h" #include "path-util.h" +#include "serialize.h" #include "string-table.h" static const char *const bpf_cgroup_attach_type_table[__MAX_BPF_ATTACH_TYPE] = { @@ -362,3 +364,139 @@ int bpf_program_get_id_by_fd(int prog_fd, uint32_t *ret_id) { return 0; }; + +int bpf_program_serialize_attachment( + FILE *f, + FDSet *fds, + const char *key, + BPFProgram *p) { + + _cleanup_free_ char *escaped = NULL; + int copy, r; + + if (!p || !p->attached_path) + return 0; + + assert(p->kernel_fd >= 0); + + escaped = cescape(p->attached_path); + if (!escaped) + return -ENOMEM; + + copy = fdset_put_dup(fds, p->kernel_fd); + if (copy < 0) + return log_error_errno(copy, "Failed to add BPF kernel fd to serialize: %m"); + + r = serialize_item_format( + f, + key, + "%i %s %s", + copy, + bpf_cgroup_attach_type_to_string(p->attached_type), + escaped); + if (r < 0) + return r; + + /* After serialization, let's forget the fact that this program is attached. The attachment — if you + * so will — is now 'owned' by the serialization, and not us anymore. Why does that matter? Because + * of BPF's less-than-ideal lifecycle handling: to detach a program from a cgroup we have to + * explicitly do so, it's not done implicitly on close(). Now, since we are serializing here we don't + * want the program to be detached while freeing things, so that the attachment can be retained after + * deserializing again. bpf_program_free() implicitly detaches things, if attached_path is non-NULL, + * hence we set it to NULL here. */ + + p->attached_path = mfree(p->attached_path); + return 0; +} + +int bpf_program_serialize_attachment_set(FILE *f, FDSet *fds, const char *key, Set *set) { + BPFProgram *p; + int r; + + SET_FOREACH(p, set) { + r = bpf_program_serialize_attachment(f, fds, key, p); + if (r < 0) + return r; + } + + return 0; +} + +int bpf_program_deserialize_attachment(const char *v, FDSet *fds, BPFProgram **bpfp) { + _cleanup_free_ char *sfd = NULL, *sat = NULL, *unescaped = NULL; + _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL; + _cleanup_close_ int fd = -1; + int ifd, at, r; + + assert(v); + assert(bpfp); + + /* Extract first word: the fd number */ + r = extract_first_word(&v, &sfd, NULL, 0); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + r = safe_atoi(sfd, &ifd); + if (r < 0) + return r; + if (ifd < 0) + return -EBADF; + + /* Extract second word: the attach type */ + r = extract_first_word(&v, &sat, NULL, 0); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + at = bpf_cgroup_attach_type_from_string(sat); + if (at < 0) + return at; + + /* The rest is the path */ + r = cunescape(v, 0, &unescaped); + if (r < 0) + return r; + + fd = fdset_remove(fds, ifd); + if (fd < 0) + return fd; + + p = new(BPFProgram, 1); + if (!p) + return -ENOMEM; + + *p = (BPFProgram) { + .n_ref = 1, + .kernel_fd = TAKE_FD(fd), + .prog_type = BPF_PROG_TYPE_UNSPEC, + .attached_path = TAKE_PTR(unescaped), + .attached_type = at, + }; + + if (*bpfp) + bpf_program_unref(*bpfp); + + *bpfp = TAKE_PTR(p); + return 0; +} + +int bpf_program_deserialize_attachment_set(const char *v, FDSet *fds, Set **bpfsetp) { + BPFProgram *p = NULL; + int r; + + assert(v); + assert(bpfsetp); + + r = bpf_program_deserialize_attachment(v, fds, &p); + if (r < 0) + return r; + + r = set_ensure_consume(bpfsetp, &bpf_program_hash_ops, p); + if (r < 0) + return r; + + return 0; +} |