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 <alex.lyn@antgroup.com>
This commit is contained in:
Alex Lyn
2026-05-26 19:48:44 +08:00
parent 63840fb006
commit 207f019bb5
4 changed files with 83 additions and 1 deletions

View File

@@ -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

View File

@@ -120,6 +120,8 @@ pub struct Sandbox {
pub network: Network,
pub mounts: Vec<String>,
pub container_mounts: HashMap<String, Vec<String>>,
/// dm-verity devices per container for cleanup
pub container_verity_devices: HashMap<String, Vec<String>>,
pub uevent_map: HashMap<String, Uevent>,
pub uevent_watchers: Vec<Option<UeventWatcher>>,
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),

View File

@@ -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;
}

View File

@@ -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/<name> (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