]> git.ipfire.org Git - pakfire.git/commitdiff
cgroups: Add BPF program to filter device node access
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 29 Jun 2023 08:21:11 +0000 (08:21 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 29 Jun 2023 08:21:11 +0000 (08:21 +0000)
This is currently permitting everything which we don't want to sustain
in the long-term.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/cgroup.c

index 4c3267cc91e908e0bcaf13d3ca6ec1de2e712107..3f6e058541dc9dc1337d02b5f6d530a924a432ec 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/bpf.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <sys/types.h>
 
+// libbpf
+#include <bpf/bpf.h>
+
 #include <pakfire/cgroup.h>
 #include <pakfire/logging.h>
 #include <pakfire/pakfire.h>
 #include <pakfire/string.h>
 #include <pakfire/util.h>
 
+static char bpf_log_buffer[BPF_LOG_BUF_SIZE];
+
 #define BUFFER_SIZE                    64 * 1024
 
+// Short form of mov, dst_reg = src_reg
+#define BPF_MOV64_IMM(DST, IMM) \
+       ((struct bpf_insn){ \
+               .code = BPF_ALU64 | BPF_MOV | BPF_K, \
+               .dst_reg = DST, \
+               .src_reg = 0, \
+               .off = 0, \
+               .imm = IMM \
+       })
+
+// Program exit
+#define BPF_EXIT_INSN() \
+       ((struct bpf_insn){ \
+               .code = BPF_JMP | BPF_EXIT, \
+               .dst_reg = 0, \
+               .src_reg = 0, \
+               .off = 0, \
+               .imm = 0 \
+       })
+
 enum pakfire_cgroup_controllers {
        PAKFIRE_CGROUP_CONTROLLER_CPU    = (1 << 0),
        PAKFIRE_CGROUP_CONTROLLER_MEMORY = (1 << 1),
@@ -60,6 +86,9 @@ struct pakfire_cgroup {
 
        // File descriptor to cgroup
        int fd;
+
+       // FD to the devices filter program
+       int devicesfd;
 };
 
 // Returns true if this is the root cgroup
@@ -174,14 +203,51 @@ static void pakfire_cgroup_free(struct pakfire_cgroup* cgroup) {
        DEBUG(cgroup->pakfire, "Releasing cgroup %s at %p\n",
                pakfire_cgroup_name(cgroup), cgroup);
 
-       // Close the file descriptor
+       // Close the file descriptors
        if (cgroup->fd > 0)
                close(cgroup->fd);
+       if (cgroup->devicesfd > 0)
+               close(cgroup->devicesfd);
 
        pakfire_unref(cgroup->pakfire);
        free(cgroup);
 }
 
+static int pakfire_cgroup_setup_devices(struct pakfire_cgroup* cgroup) {
+       LIBBPF_OPTS(bpf_prog_load_opts, opts,
+               // Log Buffer
+               .log_buf  = bpf_log_buffer,
+               .log_size = sizeof(bpf_log_buffer),
+       );
+       int r;
+
+       struct bpf_insn program[] = {
+               BPF_MOV64_IMM(BPF_REG_0, 1), // r0 = 1
+               BPF_EXIT_INSN(),             // return r0
+       };
+
+       // Load the BPF program
+       r = bpf_prog_load(BPF_PROG_TYPE_CGROUP_DEVICE, NULL, "GPL",
+               program, sizeof(program) / sizeof(*program), &opts);
+       if (r < 0) {
+               ERROR(cgroup->pakfire, "Could not load BPF program: %m\n");
+               return r;
+       }
+
+       // Store the file descriptor
+       cgroup->devicesfd = r;
+
+       // Attach the program to the cgroup
+       r = bpf_prog_attach(cgroup->devicesfd, cgroup->fd,
+               BPF_CGROUP_DEVICE, BPF_F_ALLOW_MULTI);
+       if (r) {
+               ERROR(cgroup->pakfire, "Could not attach BPF program to cgroup: %m\n");
+               return r;
+       }
+
+       return 0;
+}
+
 static int pakfire_cgroup_open_root(struct pakfire_cgroup* cgroup) {
        int fd = open(cgroup->root, O_DIRECTORY|O_PATH|O_CLOEXEC);
        if (fd < 0) {
@@ -537,6 +603,11 @@ int pakfire_cgroup_open(struct pakfire_cgroup** cgroup,
                        goto ERROR;
        }
 
+       // Setup the devices filter
+       r = pakfire_cgroup_setup_devices(c);
+       if (r)
+               goto ERROR;
+
        *cgroup = c;
        return 0;