From 3dffcfc78bc31cb70a1cb0b350ec95332ff0f2fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 24 Jan 2019 10:19:33 +0100 Subject: [PATCH] test-bpf: check if we can mlock() before trying bpf --- src/test/test-bpf.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/test-bpf.c b/src/test/test-bpf.c index 7341f7f1ea..cd8d68f215 100644 --- a/src/test/test-bpf.c +++ b/src/test/test-bpf.c @@ -2,6 +2,7 @@ #include #include +#include #include #include "bpf-firewall.h" @@ -14,6 +15,30 @@ #include "tests.h" #include "unit.h" +/* We use the same limit here that PID 1 bumps RLIMIT_MEMLOCK to if it can */ +#define CAN_MEMLOCK_SIZE (64U*1024U*1024U) + +static bool can_memlock(void) { + void *p; + bool b; + + /* Let's see if we can mlock() a larger blob of memory. BPF programs are charged against + * RLIMIT_MEMLOCK, hence let's first make sure we can lock memory at all, and skip the test if we + * cannot. Why not check RLIMIT_MEMLOCK explicitly? Because in container environments the + * RLIMIT_MEMLOCK value we see might not match the RLIMIT_MEMLOCK value actually in effect. */ + + p = mmap(NULL, CAN_MEMLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0); + if (p == MAP_FAILED) + return false; + + b = mlock(p, CAN_MEMLOCK_SIZE) >= 0; + if (b) + assert_se(munlock(p, CAN_MEMLOCK_SIZE) >= 0); + + assert_se(munmap(p, CAN_MEMLOCK_SIZE) >= 0); + return b; +} + int main(int argc, char *argv[]) { struct bpf_insn exit_insn[] = { BPF_MOV64_IMM(BPF_REG_0, 1), @@ -26,6 +51,7 @@ int main(int argc, char *argv[]) { _cleanup_(manager_freep) Manager *m = NULL; Unit *u; char log_buf[65535]; + struct rlimit rl; int r; test_setup_logging(LOG_DEBUG); @@ -33,6 +59,13 @@ int main(int argc, char *argv[]) { if (is_run_on_travis_ci()) return log_tests_skipped("test-bpf fails on Travis CI: https://github.com/systemd/systemd/issues/9666"); + assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0); + rl.rlim_cur = rl.rlim_max = MAX3(rl.rlim_cur, rl.rlim_max, CAN_MEMLOCK_SIZE); + (void) setrlimit(RLIMIT_MEMLOCK, &rl); + + if (!can_memlock()) + return log_tests_skipped("Can't use mlock(), skipping."); + r = enter_cgroup_subroot(); if (r == -ENOMEDIUM) return log_tests_skipped("cgroupfs not available");