bpf-firewall: custom BPF programs through IP(Ingress|Egress)FilterPath=

Takes a single /sys/fs/bpf/pinned_prog string as argument, but may be
specified multiple times. An empty assignment resets all previous filters.

Closes https://github.com/systemd/systemd/issues/10227
This commit is contained in:
Kai Lüke
2019-06-25 09:56:16 +02:00
committed by Lennart Poettering
parent 2d901d33a9
commit fab347489f
16 changed files with 436 additions and 7 deletions
+50 -3
View File
@@ -9,6 +9,7 @@
#include "bpf-program.h"
#include "load-fragment.h"
#include "manager.h"
#include "missing.h"
#include "rm-rf.h"
#include "service.h"
#include "test-helper.h"
@@ -42,7 +43,7 @@ static bool can_memlock(void) {
int main(int argc, char *argv[]) {
struct bpf_insn exit_insn[] = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_MOV64_IMM(BPF_REG_0, 0), /* drop */
BPF_EXIT_INSN()
};
@@ -54,6 +55,9 @@ int main(int argc, char *argv[]) {
char log_buf[65535];
struct rlimit rl;
int r;
union bpf_attr attr;
bool test_custom_filter = false;
const char *test_prog = "/sys/fs/bpf/test-dropper";
test_setup_logging(LOG_DEBUG);
@@ -88,14 +92,31 @@ int main(int argc, char *argv[]) {
return log_tests_skipped("BPF firewalling not supported");
assert_se(r > 0);
if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI)
if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
log_notice("BPF firewalling with BPF_F_ALLOW_MULTI supported. Yay!");
else
test_custom_filter = true;
} else
log_notice("BPF firewalling (though without BPF_F_ALLOW_MULTI) supported. Good.");
r = bpf_program_load_kernel(p, log_buf, ELEMENTSOF(log_buf));
assert(r >= 0);
if (test_custom_filter) {
attr = (union bpf_attr) {
.pathname = PTR_TO_UINT64(test_prog),
.bpf_fd = p->kernel_fd,
.file_flags = 0,
};
(void) unlink(test_prog);
r = bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
if (r < 0) {
log_warning_errno(errno, "BPF object pinning failed, will not run custom filter test: %m");
test_custom_filter = false;
}
}
p = bpf_program_unref(p);
/* The simple tests succeeded. Now let's try full unit-based use-case. */
@@ -175,5 +196,31 @@ int main(int argc, char *argv[]) {
assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.code != CLD_EXITED ||
SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.status != EXIT_SUCCESS);
if (test_custom_filter) {
assert_se(u = unit_new(m, sizeof(Service)));
assert_se(unit_add_name(u, "custom-filter.service") == 0);
assert_se(cc = unit_get_cgroup_context(u));
u->perpetual = true;
cc->ip_accounting = true;
assert_se(config_parse_ip_filter_bpf_progs(u->id, "filename", 1, "Service", 1, "IPIngressFilterPath", 0, test_prog, &cc->ip_filters_ingress, u) == 0);
assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "-/bin/ping -c 1 127.0.0.1 -W 5", SERVICE(u)->exec_command, u) == 0);
SERVICE(u)->type = SERVICE_ONESHOT;
u->load_state = UNIT_LOADED;
assert_se(unit_start(u) >= 0);
while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code != CLD_EXITED ||
SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.status != EXIT_SUCCESS);
(void) unlink(test_prog);
assert_se(SERVICE(u)->state == SERVICE_DEAD);
}
return 0;
}