Add abstraction model for BPF programs
authorDaniel Mack <daniel@zonque.org>
Tue, 18 Oct 2016 15:57:10 +0000 (17:57 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 22 Sep 2017 13:24:54 +0000 (15:24 +0200)
This object takes a number of bpf_insn members and wraps them together with
the in-kernel reference id. Will be needed by the firewall code.

meson.build
src/basic/bpf-program.c [new file with mode: 0644]
src/basic/bpf-program.h [new file with mode: 0644]
src/basic/meson.build
src/basic/missing_syscall.h

index 3e85442..d72fc6f 100644 (file)
@@ -443,6 +443,8 @@ foreach ident : [
                                  #include <keyutils.h>'''],
         ['copy_file_range',   '''#include <sys/syscall.h>
                                  #include <unistd.h>'''],
+        ['bpf',               '''#include <sys/syscall.h>
+                                 #include <unistd.h>'''],
         ['explicit_bzero' ,   '''#include <string.h>'''],
 ]
 
diff --git a/src/basic/bpf-program.c b/src/basic/bpf-program.c
new file mode 100644 (file)
index 0000000..9326176
--- /dev/null
@@ -0,0 +1,182 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Daniel Mack
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "bpf-program.h"
+#include "fd-util.h"
+#include "log.h"
+#include "missing.h"
+
+int bpf_program_new(uint32_t prog_type, BPFProgram **ret) {
+        _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
+
+        p = new0(BPFProgram, 1);
+        if (!p)
+                return log_oom();
+
+        p->prog_type = prog_type;
+        p->kernel_fd = -1;
+
+        *ret = p;
+        p = NULL;
+        return 0;
+}
+
+BPFProgram *bpf_program_unref(BPFProgram *p) {
+        if (!p)
+                return NULL;
+
+        safe_close(p->kernel_fd);
+        free(p->instructions);
+
+        return mfree(p);
+}
+
+int bpf_program_add_instructions(BPFProgram *p, const struct bpf_insn *instructions, size_t count) {
+
+        assert(p);
+
+        if (!GREEDY_REALLOC(p->instructions, p->allocated, p->n_instructions + count))
+                return -ENOMEM;
+
+        memcpy(p->instructions + p->n_instructions, instructions, sizeof(struct bpf_insn) * count);
+        p->n_instructions += count;
+
+        return 0;
+}
+
+int bpf_program_load_kernel(BPFProgram *p, char *log_buf, size_t log_size) {
+        union bpf_attr attr;
+
+        assert(p);
+
+        if (p->kernel_fd >= 0)
+                return -EBUSY;
+
+        attr = (union bpf_attr) {
+                .prog_type = p->prog_type,
+                .insns = PTR_TO_UINT64(p->instructions),
+                .insn_cnt = p->n_instructions,
+                .license = PTR_TO_UINT64("GPL"),
+                .log_buf = PTR_TO_UINT64(log_buf),
+                .log_level = !!log_buf,
+                .log_size = log_size,
+        };
+
+        p->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
+        if (p->kernel_fd < 0)
+                return -errno;
+
+        return 0;
+}
+
+int bpf_program_cgroup_attach(BPFProgram *p, int type, const char *path) {
+        _cleanup_close_ int fd = -1;
+        union bpf_attr attr;
+
+        assert(p);
+        assert(type >= 0);
+        assert(path);
+
+        fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        attr = (union bpf_attr) {
+                .attach_type = type,
+                .target_fd = fd,
+                .attach_bpf_fd = p->kernel_fd,
+        };
+
+        if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int bpf_program_cgroup_detach(int type, const char *path) {
+        _cleanup_close_ int fd = -1;
+        union bpf_attr attr;
+
+        assert(path);
+
+        fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        attr = (union bpf_attr) {
+                .attach_type = type,
+                .target_fd = fd,
+        };
+
+        if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags) {
+        union bpf_attr attr = {
+                .map_type = type,
+                .key_size = key_size,
+                .value_size = value_size,
+                .max_entries = max_entries,
+                .map_flags = flags,
+        };
+        int fd;
+
+        fd = bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
+        if (fd < 0)
+                return -errno;
+
+        return fd;
+}
+
+int bpf_map_update_element(int fd, const void *key, void *value) {
+
+        union bpf_attr attr = {
+                .map_fd = fd,
+                .key = PTR_TO_UINT64(key),
+                .value = PTR_TO_UINT64(value),
+        };
+
+        if (bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int bpf_map_lookup_element(int fd, const void *key, void *value) {
+
+        union bpf_attr attr = {
+                .map_fd = fd,
+                .key = PTR_TO_UINT64(key),
+                .value = PTR_TO_UINT64(value),
+        };
+
+        if (bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)) < 0)
+                return -errno;
+
+        return 0;
+}
diff --git a/src/basic/bpf-program.h b/src/basic/bpf-program.h
new file mode 100644 (file)
index 0000000..0dd150b
--- /dev/null
@@ -0,0 +1,55 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Daniel Mack
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+  [Except for the stuff copy/pasted from the kernel sources, see below]
+***/
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+
+#include "list.h"
+#include "macro.h"
+
+typedef struct BPFProgram BPFProgram;
+
+struct BPFProgram {
+        int kernel_fd;
+        uint32_t prog_type;
+
+        size_t n_instructions;
+        size_t allocated;
+        struct bpf_insn *instructions;
+};
+
+int bpf_program_new(uint32_t prog_type, BPFProgram **ret);
+BPFProgram *bpf_program_unref(BPFProgram *p);
+
+int bpf_program_add_instructions(BPFProgram *p, const struct bpf_insn *insn, size_t count);
+int bpf_program_load_kernel(BPFProgram *p, char *log_buf, size_t log_size);
+
+int bpf_program_cgroup_attach(BPFProgram *p, int type, const char *path);
+int bpf_program_cgroup_detach(int type, const char *path);
+
+int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags);
+int bpf_map_update_element(int fd, const void *key, void *value);
+int bpf_map_lookup_element(int fd, const void *key, void *value);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(BPFProgram*, bpf_program_unref);
index 67cc272..994336f 100644 (file)
@@ -1,4 +1,6 @@
 basic_sources_plain = files('''
+        MurmurHash2.c
+        MurmurHash2.h
         af-list.c
         af-list.h
         alloc-util.c
@@ -16,6 +18,8 @@ basic_sources_plain = files('''
         bitmap.c
         bitmap.h
         blkid-util.h
+        bpf-program.c
+        bpf-program.h
         btrfs-ctree.h
         btrfs-util.c
         btrfs-util.h
@@ -24,10 +28,10 @@ basic_sources_plain = files('''
         bus-label.h
         calendarspec.c
         calendarspec.h
-        capability-util.c
-        capability-util.h
         cap-list.c
         cap-list.h
+        capability-util.c
+        capability-util.h
         cgroup-util.c
         cgroup-util.h
         chattr-util.c
@@ -61,10 +65,10 @@ basic_sources_plain = files('''
         extract-word.h
         fd-util.c
         fd-util.h
-        fileio.c
-        fileio.h
         fileio-label.c
         fileio-label.h
+        fileio.c
+        fileio.h
         format-util.h
         fs-util.c
         fs-util.h
@@ -82,9 +86,9 @@ basic_sources_plain = files('''
         hostname-util.h
         in-addr-util.c
         in-addr-util.h
-        ioprio.h
         io-util.c
         io-util.h
+        ioprio.h
         journal-importer.c
         journal-importer.h
         khash.c
@@ -106,13 +110,11 @@ basic_sources_plain = files('''
         mempool.c
         mempool.h
         missing_syscall.h
+        mkdir-label.c
         mkdir.c
         mkdir.h
-        mkdir-label.c
         mount-util.c
         mount-util.h
-        MurmurHash2.c
-        MurmurHash2.h
         nss-util.h
         ordered-set.c
         ordered-set.h
@@ -138,9 +140,9 @@ basic_sources_plain = files('''
         rlimit-util.h
         rm-rf.c
         rm-rf.h
-        securebits.h
         securebits-util.c
         securebits-util.h
+        securebits.h
         selinux-util.c
         selinux-util.h
         set.h
index 898116c..17cde5e 100644 (file)
@@ -22,6 +22,8 @@
 
 /* Missing glibc definitions to access certain kernel APIs */
 
+#include <sys/types.h>
+
 #if !HAVE_DECL_PIVOT_ROOT
 static inline int pivot_root(const char *new_root, const char *put_old) {
         return syscall(SYS_pivot_root, new_root, put_old);
@@ -316,3 +318,33 @@ static inline ssize_t copy_file_range(int fd_in, loff_t *off_in,
 #  endif
 }
 #endif
+
+#if !HAVE_DECL_BPF
+#  ifndef __NR_bpf
+#    if defined __i386__
+#      define __NR_bpf 357
+#    elif defined __x86_64__
+#      define __NR_bpf 321
+#    elif defined __aarch64__
+#      define __NR_bpf 280
+#    elif defined __sparc__
+#      define __NR_bpf 349
+#    elif defined __s390__
+#      define __NR_bpf 351
+#    else
+#      warning "__NR_bpf not defined for your architecture"
+#    endif
+#  endif
+
+union bpf_attr;
+
+static inline int bpf(int cmd, union bpf_attr *attr, size_t size) {
+#ifdef __NR_bpf
+        return (int) syscall(__NR_bpf, cmd, attr, size);
+#else
+        errno = ENOSYS;
+        return -1;
+#endif
+}
+
+#endif