summaryrefslogtreecommitdiff
path: root/src/test/test-bpf-devices.c
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2019-11-09 11:50:25 +0100
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2019-11-11 15:13:38 +0100
commit7973f564687f7e6dc5bcfee09aec3cb19ed34f1d (patch)
tree8783a2a8da20de851024955c08c0bcc9e0b15533 /src/test/test-bpf-devices.c
parenta72a5326a47733f057d1bea1ddb319b779165f8d (diff)
downloadsystemd-7973f564687f7e6dc5bcfee09aec3cb19ed34f1d.tar.gz
test-bpf-devices: new test for the devices bpf code
Diffstat (limited to 'src/test/test-bpf-devices.c')
-rw-r--r--src/test/test-bpf-devices.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/test/test-bpf-devices.c b/src/test/test-bpf-devices.c
new file mode 100644
index 0000000000..aef9d359d4
--- /dev/null
+++ b/src/test/test-bpf-devices.c
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "bpf-devices.h"
+#include "bpf-program.h"
+#include "cgroup-setup.h"
+#include "errno-list.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "path-util.h"
+#include "tests.h"
+
+static void test_policy_closed(const char *cgroup_path, BPFProgram **installed_prog) {
+ _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+ unsigned wrong = 0;
+ int r;
+
+ log_info("/* %s */", __func__);
+
+ r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_CLOSED, true);
+ assert_se(r >= 0);
+
+ r = bpf_devices_whitelist_static(prog, cgroup_path);
+ assert_se(r >= 0);
+
+ r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_CLOSED, true, cgroup_path, installed_prog);
+ assert_se(r >= 0);
+
+ const char *s;
+ FOREACH_STRING(s, "/dev/null",
+ "/dev/zero",
+ "/dev/full",
+ "/dev/random",
+ "/dev/urandom",
+ "/dev/tty",
+ "/dev/ptmx") {
+ _cleanup_close_ int fd, fd2;
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd < 0 && errno == EPERM;
+ /* We ignore errors other than EPERM, e.g. ENOENT or ENXIO */
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 < 0 && errno == EPERM;
+ }
+ assert_se(wrong == 0);
+}
+
+static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_prog) {
+ _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+ unsigned wrong = 0;
+ int r;
+
+ log_info("/* %s */", __func__);
+
+ r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
+ assert_se(r >= 0);
+
+ r = bpf_devices_whitelist_device(prog, cgroup_path, "/dev/null", "rw");
+ assert_se(r >= 0);
+
+ r = bpf_devices_whitelist_device(prog, cgroup_path, "/dev/random", "r");
+ assert_se(r >= 0);
+
+ r = bpf_devices_whitelist_device(prog, cgroup_path, "/dev/zero", "w");
+ assert_se(r >= 0);
+
+ r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
+ assert_se(r >= 0);
+
+ {
+ _cleanup_close_ int fd, fd2;
+ const char *s = "/dev/null";
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd < 0;
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 < 0;
+ }
+
+ {
+ _cleanup_close_ int fd, fd2;
+ const char *s = "/dev/random";
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd < 0;
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 >= 0;
+ }
+
+ {
+ _cleanup_close_ int fd, fd2;
+ const char *s = "/dev/zero";
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd >= 0;
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 < 0;
+ }
+
+ {
+ _cleanup_close_ int fd, fd2;
+ const char *s = "/dev/full";
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd >= 0;
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 >= 0;
+ }
+
+ assert_se(wrong == 0);
+}
+
+static void test_policy_whitelist_major(const char *pattern, const char *cgroup_path, BPFProgram **installed_prog) {
+ _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+ unsigned wrong = 0;
+ int r;
+
+ log_info("/* %s(%s) */", __func__, pattern);
+
+ r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
+ assert_se(r >= 0);
+
+ r = bpf_devices_whitelist_major(prog, cgroup_path, pattern, 'c', "rw");
+ assert_se(r >= 0);
+
+ r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
+ assert_se(r >= 0);
+
+ /* /dev/null, /dev/full have major==1, /dev/tty has major==5 */
+ {
+ _cleanup_close_ int fd, fd2;
+ const char *s = "/dev/null";
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd < 0;
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 < 0;
+ }
+
+ {
+ _cleanup_close_ int fd, fd2;
+ const char *s = "/dev/full";
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd < 0;
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 < 0;
+ }
+
+ {
+ _cleanup_close_ int fd, fd2;
+ const char *s = "/dev/tty";
+
+ fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd >= 0;
+
+ fd2 = open(s, O_CLOEXEC|O_WRONLY|O_NOCTTY);
+ log_debug("open(%s, \"w\") = %d/%s", s, fd2, fd2 < 0 ? errno_to_name(errno) : "-");
+ wrong += fd2 >= 0;
+ }
+
+ assert_se(wrong == 0);
+}
+
+static void test_policy_whitelist_major_star(char type, const char *cgroup_path, BPFProgram **installed_prog) {
+ _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+ unsigned wrong = 0;
+ int r;
+
+ log_info("/* %s(type=%c) */", __func__, type);
+
+ r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
+ assert_se(r >= 0);
+
+ r = bpf_devices_whitelist_major(prog, cgroup_path, "*", type, "rw");
+ assert_se(r >= 0);
+
+ r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
+ assert_se(r >= 0);
+
+ {
+ _cleanup_close_ int fd;
+ const char *s = "/dev/null";
+
+ fd = open(s, O_CLOEXEC|O_RDWR|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ if (type == 'c')
+ wrong += fd < 0;
+ else
+ wrong += fd >= 0;
+ }
+
+ assert_se(wrong == 0);
+}
+
+int main(int argc, char *argv[]) {
+ _cleanup_free_ char *cgroup = NULL, *parent = NULL;
+ _cleanup_(rmdir_and_freep) char *controller_path = NULL;
+ CGroupMask supported;
+ struct rlimit rl;
+ int r;
+
+ test_setup_logging(LOG_DEBUG);
+
+ assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0);
+ rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, CAN_MEMLOCK_SIZE);
+ (void) setrlimit(RLIMIT_MEMLOCK, &rl);
+
+ if (!can_memlock())
+ return log_tests_skipped("Can't use mlock()");
+
+ r = enter_cgroup_subroot(&cgroup);
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
+
+ r = bpf_devices_supported();
+ if (!r)
+ return log_tests_skipped("BPF device filter not supported");
+ assert_se(r == 1);
+
+ r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, cgroup, NULL, &controller_path);
+ assert_se(r >= 0);
+
+ _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+
+ test_policy_closed(cgroup, &prog);
+ test_policy_strict(cgroup, &prog);
+
+ test_policy_whitelist_major("mem", cgroup, &prog);
+ test_policy_whitelist_major("1", cgroup, &prog);
+
+ test_policy_whitelist_major_star('c', cgroup, &prog);
+ test_policy_whitelist_major_star('b', cgroup, &prog);
+
+ assert_se(parent = dirname_malloc(cgroup));
+
+ assert_se(cg_mask_supported(&supported) >= 0);
+ r = cg_attach_everywhere(supported, parent, 0, NULL, NULL);
+ assert_se(r >= 0);
+
+ return 0;
+}