]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bpf: add helper to translate kernel error codes from libbpf
authorLuca Boccassi <bluca@debian.org>
Tue, 28 May 2024 17:59:24 +0000 (18:59 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 29 May 2024 06:29:47 +0000 (08:29 +0200)
libbpf returns error codes from the kernel unmodified, and we don't understand
them so non-fatal ones are handled as hard errors.
Add a translation helper, and start by translating 524 to EOPNOTSUPP, which is
returned when nsresourced tries to use LSM BPF hooks that are not
implemented on a given arch (in this case, arm64 is misssing trampolines).

Fixes https://github.com/systemd/systemd/issues/32170

src/core/bpf-restrict-fs.c
src/core/bpf-restrict-ifaces.c
src/core/bpf-socket-bind.c
src/nsresourced/userns-restrict.c
src/shared/bpf-dlopen.c
src/shared/bpf-dlopen.h
src/shared/bpf-link.c

index 9300c19390146a4950bfc61b1cd8bee6def2be92..d36bfb5d5ec5305b3407b70843b4e073c254441c 100644 (file)
@@ -51,7 +51,7 @@ static bool bpf_can_link_lsm_program(struct bpf_program *prog) {
         /* If bpf_program__attach_lsm fails the resulting value stores libbpf error code instead of memory
          * pointer. That is the case when the helper is called on architectures where BPF trampoline (hence
          * BPF_LSM_MAC attach type) is not supported. */
-        return sym_libbpf_get_error(link) == 0;
+        return bpf_get_error_translated(link) == 0;
 }
 
 static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) {
@@ -139,7 +139,7 @@ int bpf_restrict_fs_setup(Manager *m) {
                 return r;
 
         link = sym_bpf_program__attach_lsm(obj->progs.restrict_filesystems);
-        r = sym_libbpf_get_error(link);
+        r = bpf_get_error_translated(link);
         if (r != 0)
                 return log_error_errno(r, "bpf-restrict-fs: Failed to link '%s' LSM BPF program: %m",
                                        sym_bpf_program__name(obj->progs.restrict_filesystems));
index ddecd3f8666a5e64fd5934835ecfe86e54bf1c68..64d8d1a7e5b24ad15a1340351a66c3aa23da736a 100644 (file)
@@ -133,12 +133,12 @@ static int restrict_ifaces_install_impl(Unit *u) {
                 return -errno;
 
         ingress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_i, cgroup_fd);
-        r = sym_libbpf_get_error(ingress_link);
+        r = bpf_get_error_translated(ingress_link);
         if (r != 0)
                 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create ingress cgroup link: %m");
 
         egress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_e, cgroup_fd);
-        r = sym_libbpf_get_error(egress_link);
+        r = bpf_get_error_translated(egress_link);
         if (r != 0)
                 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create egress cgroup link: %m");
 
index 3008d8249c69f38bf84d1dd9ed87f258b49c7de0..2a1a0278d5a380012df2ca752a7b82c852886333 100644 (file)
@@ -201,13 +201,13 @@ static int socket_bind_install_impl(Unit *u) {
                 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);
+        r = bpf_get_error_translated(ipv4);
         if (r != 0)
                 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);
+        r = bpf_get_error_translated(ipv6);
         if (r != 0)
                 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));
index 241a655e62d7482f860c9b4fb82644c75661430d..be33f49f55fa41d97e21eedd54e126f51a73ab9a 100644 (file)
@@ -131,7 +131,7 @@ int userns_restrict_install(
                                 return log_oom();
 
                         link = sym_bpf_link__open(fn);
-                        r = sym_libbpf_get_error(link);
+                        r = bpf_get_error_translated(link);
                         if (r < 0) {
                                 if (r != -ENOENT)
                                         return log_error_errno(r, "Unable to open pinned program link: %m");
@@ -144,7 +144,7 @@ int userns_restrict_install(
 
                 if (!link) {
                         link = sym_bpf_program__attach(*ps->prog);
-                        r = sym_libbpf_get_error(link);
+                        r = bpf_get_error_translated(link);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to attach LSM BPF program: %m");
 
index d4ae24053eb6a7545232a8e61ecfcef1448a702a..50491fc6aa5ca9a71f1075109c6bf29bcd0855eb 100644 (file)
@@ -181,6 +181,23 @@ int dlopen_bpf(void) {
         return r;
 }
 
+int bpf_get_error_translated(const void *ptr) {
+        int r;
+
+        r = sym_libbpf_get_error(ptr);
+
+        switch (r) {
+        case -524:
+                /* Workaround for kernel bug, BPF returns an internal error instead of translating it, until
+                 * it is fixed:
+                 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/errno.h?h=v6.9&id=a38297e3fb012ddfa7ce0321a7e5a8daeb1872b6#n27
+                 */
+                return -EOPNOTSUPP;
+        default:
+                return r;
+        }
+}
+
 #else
 
 int dlopen_bpf(void) {
index 6deca829f16b85a312cbd4e525cbf87c87a9595e..df12d08e50e7dd2851af734ba5e12f4565673b9b 100644 (file)
@@ -35,13 +35,17 @@ DLSYM_PROTOTYPE(bpf_program__attach);
 DLSYM_PROTOTYPE(bpf_program__attach_cgroup);
 DLSYM_PROTOTYPE(bpf_program__attach_lsm);
 DLSYM_PROTOTYPE(bpf_program__name);
-DLSYM_PROTOTYPE(libbpf_get_error);
 DLSYM_PROTOTYPE(libbpf_set_print);
 DLSYM_PROTOTYPE(ring_buffer__epoll_fd);
 DLSYM_PROTOTYPE(ring_buffer__free);
 DLSYM_PROTOTYPE(ring_buffer__new);
 DLSYM_PROTOTYPE(ring_buffer__poll);
 
+/* libbpf sometimes returns error codes that make sense only in the kernel, like 524 for EOPNOTSUPP. Use
+ * this helper instead of libbpf_get_error() to ensure some of the known ones are translated into errnos
+ * we understand. */
+int bpf_get_error_translated(const void *ptr);
+
 #endif
 
 int dlopen_bpf(void);
index fea49b2ecbbdc7d65c76970bb5761ba50841871b..77f6a4ee9ac8bb484928655b3da686b73141c5e0 100644 (file)
@@ -16,7 +16,7 @@ bool bpf_can_link_program(struct bpf_program *prog) {
         link = sym_bpf_program__attach_cgroup(prog, /*cgroup_fd=*/-1);
 
         /* EBADF indicates that bpf_link is supported by kernel. */
-        return sym_libbpf_get_error(link) == -EBADF;
+        return bpf_get_error_translated(link) == -EBADF;
 }
 
 int bpf_serialize_link(FILE *f, FDSet *fds, const char *key, struct bpf_link *link) {
@@ -25,7 +25,7 @@ int bpf_serialize_link(FILE *f, FDSet *fds, const char *key, struct bpf_link *li
         if (!link)
                 return -ENOENT;
 
-        if (sym_libbpf_get_error(link) != 0)
+        if (bpf_get_error_translated(link) != 0)
                 return -EINVAL;
 
         return serialize_fd(f, fds, key, sym_bpf_link__fd(link));