6b000af4f2
https://tools.ietf.org/html/draft-knodel-terminology-02 https://lwn.net/Articles/823224/ This gets rid of most but not occasions of these loaded terms: 1. scsi_id and friends are something that is supposed to be removed from our tree (see #7594) 2. The test suite defines an API used by the ubuntu CI. We can remove this too later, but this needs to be done in sync with the ubuntu CI. 3. In some cases the terms are part of APIs we call or where we expose concepts the kernel names the way it names them. (In particular all remaining uses of the word "slave" in our codebase are like this, it's used by the POSIX PTY layer, by the network subsystem, the mount API and the block device subsystem). Getting rid of the term in these contexts would mean doing some major fixes of the kernel ABI first. Regarding the replacements: when whitelist/blacklist is used as noun we replace with with allow list/deny list, and when used as verb with allow-list/deny-list.
307 lines
10 KiB
C
307 lines
10 KiB
C
/* 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_allow_list_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_allow_list_device(prog, cgroup_path, "/dev/null", "rw");
|
|
assert_se(r >= 0);
|
|
|
|
r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/random", "r");
|
|
assert_se(r >= 0);
|
|
|
|
r = bpf_devices_allow_list_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_allow_list_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_allow_list_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_allow_list_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_allow_list_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);
|
|
}
|
|
|
|
static void test_policy_empty(bool add_mismatched, const char *cgroup_path, BPFProgram **installed_prog) {
|
|
_cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
|
|
unsigned wrong = 0;
|
|
int r;
|
|
|
|
log_info("/* %s(add_mismatched=%s) */", __func__, yes_no(add_mismatched));
|
|
|
|
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, add_mismatched);
|
|
assert_se(r >= 0);
|
|
|
|
if (add_mismatched) {
|
|
r = bpf_devices_allow_list_major(prog, cgroup_path, "foobarxxx", 'c', "rw");
|
|
assert_se(r < 0);
|
|
}
|
|
|
|
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, false, 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) : "-");
|
|
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);
|
|
|
|
r = cg_all_unified();
|
|
if (r <= 0)
|
|
return log_tests_skipped("We don't seem to be running with unified cgroup hierarchy");
|
|
|
|
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_allow_list_major("mem", cgroup, &prog);
|
|
test_policy_allow_list_major("1", cgroup, &prog);
|
|
|
|
test_policy_allow_list_major_star('c', cgroup, &prog);
|
|
test_policy_allow_list_major_star('b', cgroup, &prog);
|
|
|
|
test_policy_empty(false, cgroup, &prog);
|
|
test_policy_empty(true, 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;
|
|
}
|