Add abstraction model for BPF programs

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.
This commit is contained in:
Daniel Mack 2016-10-18 17:57:10 +02:00 committed by Lennart Poettering
parent 3f0c2342c0
commit 71e5200f94
5 changed files with 282 additions and 9 deletions

View 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>'''],
]

182
src/basic/bpf-program.c Normal file
View File

@ -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;
}

55
src/basic/bpf-program.h Normal file
View File

@ -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);

View 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

View 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