From f995ed28f67dd26bc8fc187f3d08aaeaa9f99267 Mon Sep 17 00:00:00 2001 From: desbma-s1n Date: Fri, 29 Sep 2023 11:11:06 +0200 Subject: [PATCH] feat: support ProtectClock systemd option --- src/strace/run.rs | 1 + src/systemd/options.rs | 12 ++++++++++++ tests/cl.rs | 13 +++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/strace/run.rs b/src/strace/run.rs index f167466..16ce8b6 100644 --- a/src/strace/run.rs +++ b/src/strace/run.rs @@ -22,6 +22,7 @@ impl Strace { nix::unistd::mkfifo(&pipe_path, nix::sys::stat::Mode::from_bits(0o600).unwrap())?; // Start process + // TODO setuid/setgid execution will be broken unless strace runs as root let child = Command::new("strace") .args([ "--daemonize=grandchild", diff --git a/src/systemd/options.rs b/src/systemd/options.rs index 5f1ca72..176f8fb 100644 --- a/src/systemd/options.rs +++ b/src/systemd/options.rs @@ -1134,6 +1134,18 @@ pub fn build_options( }], }); + // https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectClock= + options.push(OptionDescription { + name: "ProtectClock".to_string(), + possible_values: vec![OptionValueDescription { + value: OptionValue::Boolean(true), + // This option essentially does the same thing as deny @clock + desc: OptionEffect::Simple(OptionValueEffect::DenySyscalls(DenySyscalls::Class( + "clock".to_string(), + ))), + }], + }); + // https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter= // // Also change the default behavior when calling a denied syscall to return EPERM instead og killing diff --git a/tests/cl.rs b/tests/cl.rs index 13935f4..454afe5 100644 --- a/tests/cl.rs +++ b/tests/cl.rs @@ -45,6 +45,7 @@ fn run_true() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @signal:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -79,6 +80,7 @@ fn run_write_dev_null() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -113,6 +115,7 @@ fn run_ls_dev() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @signal:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -147,6 +150,7 @@ fn run_ls_proc() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @signal:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -181,6 +185,7 @@ fn run_read_kallsyms() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @signal:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -215,6 +220,7 @@ fn run_ls_modules() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @signal:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -242,6 +248,7 @@ fn run_dmesg() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @signal:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -273,6 +280,7 @@ fn run_systemctl() { .stdout(predicate::str::contains("RestrictAddressFamilies=AF_UNIX\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicates::boolean::OrPredicate::new( predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1), predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1), @@ -310,6 +318,7 @@ fn run_ss() { .stdout(predicate::str::contains("RestrictAddressFamilies=AF_NETLINK AF_UNIX\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @signal:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -338,6 +347,7 @@ fn run_mmap_wx() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); Command::cargo_bin(env!("CARGO_PKG_NAME")) @@ -363,6 +373,7 @@ fn run_mmap_wx() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @resources:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); } @@ -394,6 +405,7 @@ fn run_sched_realtime() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=").not()) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); Command::cargo_bin(env!("CARGO_PKG_NAME")) @@ -419,5 +431,6 @@ fn run_sched_realtime() { .stdout(predicate::str::contains("RestrictAddressFamilies=none\n").count(1)) .stdout(predicate::str::contains("LockPersonality=true\n").count(1)) .stdout(predicate::str::contains("RestrictRealtime=true\n").count(1)) + .stdout(predicate::str::contains("ProtectClock=true\n").count(1)) .stdout(predicate::str::contains("SystemCallFilter=~@aio:EPERM @chown:EPERM @clock:EPERM @cpu-emulation:EPERM @debug:EPERM @io-event:EPERM @ipc:EPERM @keyring:EPERM @memlock:EPERM @module:EPERM @mount:EPERM @network-io:EPERM @obsolete:EPERM @pkey:EPERM @privileged:EPERM @process:EPERM @raw-io:EPERM @reboot:EPERM @sandbox:EPERM @setuid:EPERM @swap:EPERM @sync:EPERM @timer:EPERM\n").count(1)); }