Name native identity fields that drift

This commit is contained in:
Meta Vens 2026-09-28 17:02:46 +02:00
commit 5e94eb82f0

View file

@ -2407,6 +2407,76 @@ pub struct SystemdTransientWorkloadDriver {
pub credential_root: PathBuf,
}
fn changed_systemd_workload_fields(
observed: &SystemdWorkloadObservation,
prior: &SystemdWorkloadObservation,
) -> Vec<&'static str> {
let mut changed_fields = Vec::new();
macro_rules! record_changed_fields {
($($field:ident),+ $(,)?) => {
$(
if observed.$field != prior.$field {
changed_fields.push(stringify!($field));
}
)+
};
}
record_changed_fields!(
unit,
unit_description,
invocation_id,
exec_main_start_timestamp_monotonic,
service_type,
restart_policy,
kill_mode,
dynamic_user,
systemd_user,
systemd_group,
supplementary_groups,
capability_bounding_set,
ambient_capabilities,
private_mounts,
private_pids,
protect_proc,
proc_subset,
no_new_privileges,
umask,
inaccessible_paths,
load_credential,
main_pid,
process_start_time,
process_uids,
process_gids,
process_groups,
process_cap_inheritable,
process_cap_permitted,
process_cap_effective,
process_cap_bounding,
process_cap_ambient,
process_no_new_privileges,
process_namespace_pids,
mount_namespace_id,
pid_namespace_id,
executable,
executable_device,
executable_inode,
executable_sha256,
runtime_instance_id,
working_directory,
runtime_bundle,
command_line_sha256,
environment_names,
environment_contract_sha256,
control_group,
credentials_directory,
parent_only_file_descriptors,
activation_signer_identity_id,
activation_signer_public_key,
service_credentials,
);
changed_fields
}
fn systemd_group_matches_launch_contract(
expected_group: Option<(&str, u32)>,
observed_group: &str,
@ -3859,72 +3929,9 @@ impl WorkloadPort for SystemdTransientWorkloadDriver {
&prior.parent_only_file_descriptors,
)?;
if observed != *prior {
let mut changed_fields = Vec::new();
macro_rules! record_changed_fields {
($($field:ident),+ $(,)?) => {
$(
if observed.$field != prior.$field {
changed_fields.push(stringify!($field));
}
)+
};
}
record_changed_fields!(
unit,
unit_description,
invocation_id,
exec_main_start_timestamp_monotonic,
service_type,
restart_policy,
kill_mode,
dynamic_user,
systemd_user,
systemd_group,
supplementary_groups,
capability_bounding_set,
ambient_capabilities,
private_mounts,
private_pids,
protect_proc,
proc_subset,
no_new_privileges,
umask,
inaccessible_paths,
load_credential,
main_pid,
process_start_time,
process_uids,
process_gids,
process_groups,
process_cap_inheritable,
process_cap_permitted,
process_cap_effective,
process_cap_bounding,
process_cap_ambient,
process_no_new_privileges,
process_namespace_pids,
mount_namespace_id,
pid_namespace_id,
executable,
executable_device,
executable_inode,
executable_sha256,
runtime_instance_id,
working_directory,
runtime_bundle,
command_line_sha256,
environment_names,
environment_contract_sha256,
control_group,
credentials_directory,
parent_only_file_descriptors,
activation_signer_identity_id,
activation_signer_public_key,
service_credentials,
);
bail!(
"native workload identity changed after observation: {}",
changed_fields.join(", ")
changed_systemd_workload_fields(&observed, prior).join(", ")
);
}
ensure!(
@ -3991,10 +3998,12 @@ impl WorkloadPort for SystemdTransientWorkloadDriver {
.collect::<Vec<_>>(),
&observation.parent_only_file_descriptors,
)?;
ensure!(
current == *observation,
"refusing to stop a workload whose native identity changed"
);
if current != *observation {
bail!(
"refusing to stop a workload whose native identity changed: {}",
changed_systemd_workload_fields(&current, observation).join(", ")
);
}
} else {
ensure!(
values.get("InvocationID") == Some(&observation.invocation_id)
@ -8200,6 +8209,19 @@ mod tests {
Ok(())
}
#[test]
fn workload_identity_diagnostic_names_only_changed_fields() {
let prior = systemd_audit_observation("no", 61_000);
let mut observed = prior.clone();
observed.main_pid += 1;
observed.command_line_sha256 = format!("sha256-{}", "f".repeat(64));
assert_eq!(
changed_systemd_workload_fields(&observed, &prior),
vec!["main_pid", "command_line_sha256"]
);
}
#[test]
fn host_isolation_is_two_live_distinct_processes_on_one_host() {
let live = |pid: u32, created: u64| {