From d42ba348e903ffc9ab53f10d1469c3d0c354c135 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Wed, 15 Oct 2025 18:18:22 +0100 Subject: [PATCH 1/2] rego: Allow sending SIGTERM and SIGKILL to the container init process in old policies We used to allow SIGTERM/SIGKILL the container init process even if the container's signals list is empty due to a bug fixed in #2538. However, because our tooling has been generating policies with an empty signals list, we need to special case this for old policies to maintain backwards compatibility. Update framework.rego to have SIGTERM and SIGKILL as default kill signals for init process for framework API versions "0.4.1" and below. Newer policies must explicitly have these signals present, otherwise sending signal will be denied. Signed-off-by: Tingmao Wang Co-authored-by: Maksim An --- pkg/securitypolicy/framework.rego | 12 +++++++++++- pkg/securitypolicy/version_framework | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pkg/securitypolicy/framework.rego b/pkg/securitypolicy/framework.rego index 8a28f3e312..771c5c7bb3 100644 --- a/pkg/securitypolicy/framework.rego +++ b/pkg/securitypolicy/framework.rego @@ -1960,7 +1960,7 @@ check_container(raw_container, framework_version) := container { "allow_elevated": raw_container.allow_elevated, "working_dir": raw_container.working_dir, "exec_processes": raw_container.exec_processes, - "signals": raw_container.signals, + "signals": check_signals(raw_container, framework_version), "allow_stdio_access": raw_container.allow_stdio_access, # Additional fields need to have default logic applied "no_new_privileges": check_no_new_privileges(raw_container, framework_version), @@ -2026,6 +2026,16 @@ check_seccomp_profile_sha256(raw_container, framework_version) := seccomp_profil seccomp_profile_sha256 := "" } +check_signals(raw_container, framework_version) := signals { + semver.compare(framework_version, "0.4.1") >= 0 + signals := raw_container.signals +} + +check_signals(raw_container, framework_version) := signals { + semver.compare(framework_version, "0.4.1") < 0 + signals := array.concat(raw_container.signals, [9, 15]) +} + check_external_process(raw_process, framework_version) := process { semver.compare(framework_version, version) == 0 process := raw_process diff --git a/pkg/securitypolicy/version_framework b/pkg/securitypolicy/version_framework index 60a2d3e96c..44bb5d1f74 100644 --- a/pkg/securitypolicy/version_framework +++ b/pkg/securitypolicy/version_framework @@ -1 +1 @@ -0.4.0 \ No newline at end of file +0.4.1 \ No newline at end of file From f042c0552b196172097566e855f59c01f44086eb Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Wed, 15 Oct 2025 15:08:15 +0100 Subject: [PATCH 2/2] Fix missing denial reason when a signal request to a non-init process is denied This happens if the container.signals list contains relevant signals, but the process's signals list does not allow the signal. Old: {"decision":"deny","input":{"argList":["/bin/sleep","infinity"],"containerID":"0971693a04cdd4f2eeefc569754b5cd8046ec0b7c7ed6899bb3dec0dd45ba735","isInitProcess":false,"rule":"signal_container_process","signal":9},"reason":{"errors":[]}} Now: {"decision":"deny","input":{"argList":["/bin/sleep","infinity"],"containerID":"3873bfc939e2415892b5b74a7b1dbade0f7222e266df43df85968ddda59be56e","isInitProcess":false,"rule":"signal_container_process","signal":9},"reason":{"errors":["target isn't allowed to receive the signal"]}} Signed-off-by: Tingmao Wang --- pkg/securitypolicy/framework.rego | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/securitypolicy/framework.rego b/pkg/securitypolicy/framework.rego index 771c5c7bb3..77903b9ee6 100644 --- a/pkg/securitypolicy/framework.rego +++ b/pkg/securitypolicy/framework.rego @@ -1488,11 +1488,13 @@ errors[mountError] { default signal_allowed := false signal_allowed { + input.isInitProcess some container in data.metadata.matches[input.containerID] signal_ok(container.signals) } signal_allowed { + not input.isInitProcess some container in data.metadata.matches[input.containerID] some process in container.exec_processes command_ok(process.command)