]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bpf-program: check if a trivial BPF program can be created and loaded
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 23 May 2025 17:38:46 +0000 (02:38 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 27 May 2025 16:24:33 +0000 (17:24 +0100)
Re-introduce the check dropped by
ec3c5cfac74e8361a3b0153cc9e8cfdbbcbde0c6,
ad446c8ceb97c03971f06fd43e97720afe33be5a.

For some reasons, if we are running on LXC, even if bpf_program_supported()
returned true, but bpf_program_load_kernel() failed:
```
Attaching device control BPF program to cgroup /system.slice/test-bpf-devices-875b406d56ac7bc3.scope/186c411f6e991777 failed: Operation not permitted
src/test/test-bpf-devices.c:31: Assertion failed: Expected "r" to succeed, but got error: Operation not permitted
```

src/shared/bpf-program.c

index d369b008fd2066d4069cc024170832ee384f2158..5c4bea60c6b1ba987554f6f4488779aa74162db6 100644 (file)
@@ -49,6 +49,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(bpf_program_hash_ops, void, trivial_hash_fun
 
 int bpf_program_supported(void) {
         static int cached = 0;
+        int r;
 
         if (cached != 0)
                 return cached;
@@ -57,10 +58,26 @@ int bpf_program_supported(void) {
          * - BPF_PROG_TYPE_CGROUP_SKB, supported since kernel v4.10 (0e33661de493db325435d565a4a722120ae4cbf3),
          * - BPF_PROG_TYPE_CGROUP_DEVICE, supported since kernel v4.15 (ebc614f687369f9df99828572b1d85a7c2de3d92),
          * - BPF_PROG_TYPE_CGROUP_SOCK_ADDR, supported since kernel v4.17 (4fbac77d2d092b475dda9eea66da674369665427).
-         * Hence, as our baseline on the kernel is v5.4, it is not necessary to check if we can create BPF
-         * programs of hthese types.
-         *
-         * However, unfortunately the kernel allows us to create BPF_PROG_TYPE_CGROUP_SKB (maybe also other types)
+         * As our baseline on the kernel is v5.4, it is enough to check if one BPF program can be created and loaded. */
+
+        _cleanup_(bpf_program_freep) BPFProgram *program = NULL;
+        r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, /* prog_name = */ NULL, &program);
+        if (r < 0)
+                return cached = log_debug_errno(r, "Can't allocate CGROUP SKB BPF program, assuming BPF is not supported: %m");
+
+        static const struct bpf_insn trivial[] = {
+                BPF_MOV64_IMM(BPF_REG_0, 1),
+                BPF_EXIT_INSN()
+        };
+        r = bpf_program_add_instructions(program, trivial, ELEMENTSOF(trivial));
+        if (r < 0)
+                return cached = log_debug_errno(r, "Can't add trivial instructions to CGROUP SKB BPF program, assuming BPF is not supported: %m");
+
+        r = bpf_program_load_kernel(program, /* log_buf = */ NULL, /* log_size = */ 0);
+        if (r < 0)
+                return cached = log_debug_errno(r, "Can't load kernel CGROUP SKB BPF program, assuming BPF is not supported: %m");
+
+        /* Unfortunately the kernel allows us to create BPF_PROG_TYPE_CGROUP_SKB (maybe also other types)
          * programs even when CONFIG_CGROUP_BPF is turned off at kernel compilation time. This sucks of course:
          * why does it allow us to create a cgroup BPF program if we can't do a thing with it later?
          *