From 207f019bb5e2dbcae2e0eccc8ff4371523afe197 Mon Sep 17 00:00:00 2001 From: Alex Lyn Date: Tue, 26 May 2026 19:48:44 +0800 Subject: [PATCH] kata-agent: Add dm-verity device cleanup for GPT-partitioned layers Add per-container verity_devices tracking in Sandbox and wire the teardown path: destroy_partition_dmverity_device removes the device-mapper target via deferred-remove ioctl and deletes the mknod node, cleanup_dmverity_devices iterates all devices in reverse order. Wire into remove_container_resources (rpc.rs) so verity devices are torn down after unmount, and record verity device paths in add_storages (storage/mod.rs) for tracking. Signed-off-by: Alex Lyn --- src/agent/src/rpc.rs | 10 ++++ src/agent/src/sandbox.rs | 3 ++ src/agent/src/storage/mod.rs | 15 +++++- src/agent/src/storage/multi_layer_erofs.rs | 56 ++++++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index 06cadc21ee..88d645250d 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -87,6 +87,7 @@ use crate::passfd_io; use crate::pci; use crate::random; use crate::sandbox::{Sandbox, SandboxError}; +use crate::storage::multi_layer_erofs::cleanup_dmverity_devices; use crate::storage::{add_storages, update_ephemeral_mounts, STORAGE_HANDLERS}; use crate::util; use crate::version::{AGENT_VERSION, API_VERSION}; @@ -2097,6 +2098,15 @@ async fn remove_container_resources(sandbox: &mut Sandbox, cid: &str) -> Result< } } + // Cleanup dm-verity devices for this container (after all mounts are unmounted) + if let Some(verity_devices) = sandbox.container_verity_devices.remove(cid) { + if !verity_devices.is_empty() { + // Cleanup dm-verity devices for this container, ignoring any errors + // since we want to proceed with cleanup as much as possible + cleanup_dmverity_devices(&verity_devices, &sandbox.logger); + } + } + sandbox.container_mounts.remove(cid); sandbox.containers.remove(cid); // Remove any host -> guest mappings for this container diff --git a/src/agent/src/sandbox.rs b/src/agent/src/sandbox.rs index 1947e24f3c..e03aa82720 100644 --- a/src/agent/src/sandbox.rs +++ b/src/agent/src/sandbox.rs @@ -120,6 +120,8 @@ pub struct Sandbox { pub network: Network, pub mounts: Vec, pub container_mounts: HashMap>, + /// dm-verity devices per container for cleanup + pub container_verity_devices: HashMap>, pub uevent_map: HashMap, pub uevent_watchers: Vec>, pub shared_utsns: Namespace, @@ -154,6 +156,7 @@ impl Sandbox { containers: HashMap::new(), mounts: Vec::new(), container_mounts: HashMap::new(), + container_verity_devices: HashMap::new(), uevent_map: HashMap::new(), uevent_watchers: Vec::new(), shared_utsns: Namespace::new(&logger), diff --git a/src/agent/src/storage/mod.rs b/src/agent/src/storage/mod.rs index 48eb4bfe37..1b8b8a9ba3 100644 --- a/src/agent/src/storage/mod.rs +++ b/src/agent/src/storage/mod.rs @@ -305,7 +305,20 @@ pub async fn add_storages( } } mount_list.extend(result.temp_mount_points); - mount_list.extend(result.verity_devices); + mount_list.extend(result.verity_devices.clone()); + + // Record verity devices for cleanup + if let Some(ref cid) = cid { + if !result.verity_devices.is_empty() { + let mut sandbox_guard = sandbox.lock().await; + sandbox_guard + .container_verity_devices + .entry(cid.clone()) + .or_insert_with(Vec::new) + .extend(result.verity_devices.clone()); + } + } + continue; } diff --git a/src/agent/src/storage/multi_layer_erofs.rs b/src/agent/src/storage/multi_layer_erofs.rs index fd17180ab8..ca9c368568 100644 --- a/src/agent/src/storage/multi_layer_erofs.rs +++ b/src/agent/src/storage/multi_layer_erofs.rs @@ -741,6 +741,62 @@ fn create_dmverity_device(verity_info: &DmVerityInfo, source_device_path: &Path) Ok(dev_path) } +/// Destroy a dm-verity device +fn destroy_dmverity_device(verity_device_name: &str) -> Result<()> { + let dm = devicemapper::DM::new()?; + let name = devicemapper::DmName::new(verity_device_name)?; + + dm.device_remove(&devicemapper::DevId::Name(name), dm_opts_deferred_remove()) + .context(format!("remove DmverityDevice {}", verity_device_name))?; + + Ok(()) +} + +/// Destroy dm-verity device by path +fn destroy_partition_dmverity_device(verity_device_path: &str, logger: &Logger) -> Result<()> { + // The verity device path is /dev/mapper/ (as created by create_dm_dev_node). + // Extract the DM device name for removal. Also remove the mknod-created device node. + let device_name = verity_device_path + .strip_prefix("/dev/mapper/") + .unwrap_or(verity_device_path) + .to_string(); + + destroy_dmverity_device(&device_name).context("Failed to destroy dm-verity device")?; + info!( + logger, + "Destroying dm-verity device"; + "device-name" => &device_name, + ); + + // Remove the device node we created with mknod. + remove_dm_dev_node(verity_device_path); + + Ok(()) +} + +/// Cleanup all dm-verity devices for a multi-layer EROFS mount +pub fn cleanup_dmverity_devices(verity_devices: &[String], logger: &Logger) { + info!( + logger, + "Cleaning up {} dm-verity devices", + verity_devices.len() + ); + + // Destroy in reverse order + for verity_device in verity_devices.iter().rev() { + if let Err(e) = destroy_partition_dmverity_device(verity_device, logger) { + warn!( + logger, + "Failed to destroy dm-verity device"; + "device-path" => verity_device, + "error" => format!("{:#}", e), + ); + } + } + + info!(logger, "dm-verity device cleanup completed"); +} + /// Validate that a container ID does not contain path traversal sequences. /// /// Container IDs are used to construct filesystem paths. A malicious ID containing