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:
committed by
Lennart Poettering
parent
2d901d33a9
commit
fab347489f
+50
-3
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user