use serde_json::json;
use sysknife_daemon::executor::{build_action_spec, ExecutorError};
const PROTECTIVE: &[&str] = &[
"lockdown=confidentiality",
"module.sig_enforce=1",
"selinux=1",
"enforcing=1",
"pti=on",
"mitigations=auto,nosmt",
"init_on_alloc=1",
"slab_nomerge",
"randomize_kstack_offset=on",
"vsyscall=none",
];
const WEAKENING: &[&str] = &["mitigations=off", "selinux=0", "pti=off", "init=/bin/sh"];
const PROTECTIVE_BARE: &[&str] = &["slab_nomerge", "nosmt", "kaslr"];
const WEAKENING_BARE: &[&str] = &["single", "nosmap", "nosmep"];
#[test]
fn set_kernel_arguments_refuses_to_remove_a_protective_arg() {
for arg in PROTECTIVE {
let params = json!({ "add": [], "remove": [arg] });
let result = build_action_spec("SetKernelArguments", ¶ms);
assert!(
matches!(result, Err(ExecutorError::InvalidParam("remove"))),
"SetKernelArguments must refuse to remove {arg}, got {result:?}"
);
}
}
#[test]
fn set_kernel_arguments_still_removes_a_weakening_arg() {
for arg in WEAKENING {
let params = json!({ "add": [], "remove": [arg] });
assert!(
build_action_spec("SetKernelArguments", ¶ms).is_ok(),
"SetKernelArguments must still be able to remove {arg}"
);
}
}
#[test]
fn grub_set_kargs_refuses_to_delete_a_protective_arg() {
for arg in PROTECTIVE_BARE {
let params = json!({ "append": [], "delete": [arg] });
let result = build_action_spec("GrubSetKargs", ¶ms);
assert!(
matches!(result, Err(ExecutorError::InvalidParam("delete"))),
"GrubSetKargs must refuse to delete {arg}, got {result:?}"
);
}
}
#[test]
fn grub_set_kargs_still_deletes_a_weakening_arg() {
for arg in WEAKENING_BARE {
let params = json!({ "append": [], "delete": [arg] });
assert!(
build_action_spec("GrubSetKargs", ¶ms).is_ok(),
"GrubSetKargs must still be able to delete {arg}"
);
}
}
#[test]
fn no_root_shell_unit_can_be_reached_through_a_kernel_argument() {
for unit in [
"systemd.unit=emergency.target",
"systemd.unit=rescue.target",
"systemd.unit=single",
"systemd.unit=debug-shell.service",
"systemd.unit=runlevel1.target",
"systemd.unit=Debug-Shell.service",
] {
let params = json!({ "add": [unit], "remove": [] });
let result = build_action_spec("SetKernelArguments", ¶ms);
assert!(
matches!(result, Err(ExecutorError::InvalidParam("add"))),
"{unit} boots the host into a root shell and must be refused, got {result:?}"
);
}
}
#[test]
fn the_debug_shell_cannot_be_reached_by_its_own_kernel_argument() {
for arg in [
"systemd.debug_shell=1",
"systemd.debug_shell",
"rd.systemd.debug_shell=1",
"systemd.debug-shell=1",
"SYSTEMD.DEBUG_SHELL=1",
] {
let params = json!({ "add": [arg], "remove": [] });
let result = build_action_spec("SetKernelArguments", ¶ms);
assert!(
matches!(result, Err(ExecutorError::InvalidParam("add"))),
"{arg} spawns a root shell on tty9 at boot and must be refused, got {result:?}"
);
}
}
#[test]
fn the_two_root_shell_screens_cannot_drift_apart() {
for unit in ["debug-shell", "emergency", "rescue", "runlevel1", "single"] {
let karg = json!({ "add": [format!("systemd.unit={unit}.target")], "remove": [] });
assert!(
build_action_spec("SetKernelArguments", &karg).is_err(),
"{unit} is reachable as a kernel argument"
);
if unit == "single" {
continue;
}
let start = json!({ "unit": format!("{unit}.service") });
assert!(
build_action_spec("StartService", &start).is_err(),
"{unit} is startable as a service"
);
}
}