diff --git a/SPECS/cloud-hypervisor-cvm/CVE-2026-27211.patch b/SPECS/cloud-hypervisor-cvm/CVE-2026-27211.patch new file mode 100644 index 00000000000..193912956b2 --- /dev/null +++ b/SPECS/cloud-hypervisor-cvm/CVE-2026-27211.patch @@ -0,0 +1,287 @@ +From 69e16ca82cdcd7ad3c4361223a4754cc8ce7f672 Mon Sep 17 00:00:00 2001 +From: Rob Bradford +Date: Sun, 8 Feb 2026 21:14:28 +0000 +Subject: [PATCH] vmm: Add option to control backing files + +Backing files (e.g. for QCOW2) interact badly with landlock since they +are not obvious from the initial VM configuration. Only enable their use +with an explicit option. + +Signed-off-by: Rob Bradford + +Upstream Patch reference: https://github.com/microsoft/cloud-hypervisor/commit/69e16ca82cdcd7ad3c4361223a4754cc8ce7f672.patch +--- + block/src/lib.rs | 1 + + block/src/qcow/mod.rs | 20 +++++++++++++++++++- + block/src/qcow_sync.rs | 14 ++++++++++---- + tests/integration.rs | 21 +++++++++++---------- + vmm/src/config.rs | 14 ++++++++++++-- + vmm/src/device_manager.rs | 6 +++++- + vmm/src/vm_config.rs | 2 ++ + 7 files changed, 60 insertions(+), 18 deletions(-) + +diff --git a/block/src/lib.rs b/block/src/lib.rs +index 45db0e4..a22bda3 100644 +--- a/block/src/lib.rs ++++ b/block/src/lib.rs +@@ -764,6 +764,7 @@ where + fn file(&mut self) -> MutexGuard; + } + ++#[derive(PartialEq, Eq, Debug)] + pub enum ImageType { + FixedVhd, + Qcow2, +diff --git a/block/src/qcow/mod.rs b/block/src/qcow/mod.rs +index 264244c..f99fcfd 100644 +--- a/block/src/qcow/mod.rs ++++ b/block/src/qcow/mod.rs +@@ -50,6 +50,7 @@ pub enum Error { + InvalidOffset(u64), + InvalidRefcountTableOffset, + InvalidRefcountTableSize(u64), ++ MaxNestingDepthExceeded, + NoFreeClusters, + NoRefcountClusters, + NotEnoughSpaceForRefcounts, +@@ -103,6 +104,7 @@ impl Display for Error { + InvalidOffset(_) => write!(f, "invalid offset"), + InvalidRefcountTableOffset => write!(f, "invalid refcount table offset"), + InvalidRefcountTableSize(size) => write!(f, "invalid refcount table size: {size}"), ++ MaxNestingDepthExceeded => write!(f, "Maximum disk nesting depth exceeded"), + NoFreeClusters => write!(f, "no free clusters"), + NoRefcountClusters => write!(f, "no refcount clusters"), + NotEnoughSpaceForRefcounts => write!(f, "not enough space for refcounts"), +@@ -134,6 +136,9 @@ pub enum ImageType { + Qcow2, + } + ++/// Nesting depth limit for disk formats that can open other disk files. ++const MAX_NESTING_DEPTH: u32 = 10; ++ + // Maximum data size supported. + const MAX_QCOW_FILE_SIZE: u64 = 0x01 << 44; // 16 TB. + +@@ -450,7 +455,15 @@ pub struct QcowFile { + + impl QcowFile { + /// Creates a QcowFile from `file`. File must be a valid qcow2 image. +- pub fn from(mut file: RawFile) -> Result { ++ /// ++ /// Additionally, max nesting depth of this qcow2 image will be set to default value 10 ++ pub fn from(file: RawFile) -> Result { ++ Self::from_with_nesting_depth(file, MAX_NESTING_DEPTH) ++ } ++ ++ /// Creates a QcowFile from `file` and with a max nesting depth. File must be a valid qcow2 ++ /// image. ++ pub fn from_with_nesting_depth(mut file: RawFile, max_nesting_depth: u32) -> Result { + let header = QcowHeader::new(&mut file)?; + + // Only v2 and v3 files are supported. +@@ -477,6 +490,11 @@ impl QcowFile { + let direct_io = file.is_direct(); + + let backing_file = if let Some(backing_file_path) = header.backing_file_path.as_ref() { ++ // Check nesting depth - applies to any backing file ++ if max_nesting_depth == 0 { ++ return Err(Error::MaxNestingDepthExceeded); ++ } ++ + let path = backing_file_path.clone(); + let backing_raw_file = OpenOptions::new() + .read(true) +diff --git a/block/src/qcow_sync.rs b/block/src/qcow_sync.rs +index 6455be6..5253adb 100644 +--- a/block/src/qcow_sync.rs ++++ b/block/src/qcow_sync.rs +@@ -16,10 +16,16 @@ pub struct QcowDiskSync { + } + + impl QcowDiskSync { +- pub fn new(file: File, direct_io: bool) -> QcowResult { +- Ok(QcowDiskSync { +- qcow_file: Arc::new(Mutex::new(QcowFile::from(RawFile::new(file, direct_io))?)), +- }) ++ pub fn new(file: File, direct_io: bool, backing_files: bool) -> QcowResult { ++ if backing_files { ++ Ok(QcowDiskSync { ++ qcow_file: Arc::new(Mutex::new(QcowFile::from(RawFile::new(file, direct_io))?)), ++ }) ++ } else { ++ Ok(QcowDiskSync { ++ qcow_file: Arc::new(Mutex::new(QcowFile::from_with_nesting_depth(RawFile::new(file, direct_io), 0)?)), ++ }) ++ } + } + } + +diff --git a/tests/integration.rs b/tests/integration.rs +index ae98f36..da6c858 100644 +--- a/tests/integration.rs ++++ b/tests/integration.rs +@@ -3350,7 +3350,7 @@ mod common_parallel { + handle_child_output(r, &output); + } + +- fn _test_virtio_block(image_name: &str, disable_io_uring: bool, disable_aio: bool) { ++ fn _test_virtio_block(image_name: &str, disable_io_uring: bool, disable_aio: bool, backing_files: bool) { + let focal = UbuntuDiskConfig::new(image_name.to_string()); + let guest = Guest::new(Box::new(focal)); + +@@ -3366,8 +3366,9 @@ mod common_parallel { + .args([ + "--disk", + format!( +- "path={}", +- guest.disk_config.disk(DiskType::OperatingSystem).unwrap() ++ "path={},backing_files={}", ++ guest.disk_config.disk(DiskType::OperatingSystem).unwrap(), ++ if backing_files { "on"} else {"off"} + ) + .as_str(), + format!( +@@ -3443,27 +3444,27 @@ mod common_parallel { + + #[test] + fn test_virtio_block_io_uring() { +- _test_virtio_block(FOCAL_IMAGE_NAME, false, true) ++ _test_virtio_block(FOCAL_IMAGE_NAME, false, true, false) + } + + #[test] + fn test_virtio_block_aio() { +- _test_virtio_block(FOCAL_IMAGE_NAME, true, false) ++ _test_virtio_block(FOCAL_IMAGE_NAME, true, false, false) + } + + #[test] + fn test_virtio_block_sync() { +- _test_virtio_block(FOCAL_IMAGE_NAME, true, true) ++ _test_virtio_block(FOCAL_IMAGE_NAME, true, true, false) + } + + #[test] + fn test_virtio_block_qcow2() { +- _test_virtio_block(FOCAL_IMAGE_NAME_QCOW2, false, false) ++ _test_virtio_block(FOCAL_IMAGE_NAME_QCOW2, false, false, false) + } + + #[test] + fn test_virtio_block_qcow2_backing_file() { +- _test_virtio_block(FOCAL_IMAGE_NAME_QCOW2_BACKING_FILE, false, false) ++ _test_virtio_block(FOCAL_IMAGE_NAME_QCOW2_BACKING_FILE, false, false, true) + } + + #[test] +@@ -3488,7 +3489,7 @@ mod common_parallel { + .output() + .expect("Expect generating VHD image from RAW image"); + +- _test_virtio_block(FOCAL_IMAGE_NAME_VHD, false, false) ++ _test_virtio_block(FOCAL_IMAGE_NAME_VHD, false, false, false) + } + + #[test] +@@ -3512,7 +3513,7 @@ mod common_parallel { + .output() + .expect("Expect generating dynamic VHDx image from RAW image"); + +- _test_virtio_block(FOCAL_IMAGE_NAME_VHDX, false, false) ++ _test_virtio_block(FOCAL_IMAGE_NAME_VHDX, false, false, false) + } + + #[test] +diff --git a/vmm/src/config.rs b/vmm/src/config.rs +index 1c70a26..cceac98 100644 +--- a/vmm/src/config.rs ++++ b/vmm/src/config.rs +@@ -1014,7 +1014,8 @@ impl DiskConfig { + bw_size=,bw_one_time_burst=,bw_refill_time=,\ + ops_size=,ops_one_time_burst=,ops_refill_time=,\ + id=,pci_segment=,rate_limit_group=,\ +- queue_affinity="; ++ queue_affinity=,\ ++ backing_files=on|off"; + + pub fn parse(disk: &str) -> Result { + let mut parser = OptionParser::new(); +@@ -1039,7 +1040,8 @@ impl DiskConfig { + .add("pci_segment") + .add("serial") + .add("rate_limit_group") +- .add("queue_affinity"); ++ .add("queue_affinity") ++ .add("backing_files"); + parser.parse(disk).map_err(Error::ParseDisk)?; + + let path = parser.get("path").map(PathBuf::from); +@@ -1124,6 +1126,12 @@ impl DiskConfig { + }) + .collect() + }); ++ let backing_files = parser ++ .convert::("backing_files") ++ .map_err(Error::ParseDisk)? ++ .unwrap_or(Toggle(false)) ++ .0; ++ + let bw_tb_config = if bw_size != 0 && bw_refill_time != 0 { + Some(TokenBucketConfig { + size: bw_size, +@@ -1168,6 +1176,7 @@ impl DiskConfig { + pci_segment, + serial, + queue_affinity, ++ backing_files, + }) + } + +@@ -2961,6 +2970,7 @@ mod tests { + pci_segment: 0, + serial: None, + queue_affinity: None, ++ backing_files: false, + } + } + +diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs +index 7330fa3..2bb95f4 100644 +--- a/vmm/src/device_manager.rs ++++ b/vmm/src/device_manager.rs +@@ -2442,6 +2442,10 @@ impl DeviceManager { + let image_type = + detect_image_type(&mut file).map_err(DeviceManagerError::DetectImageType)?; + ++ if image_type != ImageType::Qcow2 && disk_cfg.backing_files { ++ warn!("Enabling backing_files option only applies for QCOW2 files"); ++ } ++ + let image = match image_type { + ImageType::FixedVhd => { + // Use asynchronous backend relying on io_uring if the +@@ -2495,7 +2499,7 @@ impl DeviceManager { + ImageType::Qcow2 => { + info!("Using synchronous QCOW disk file"); + Box::new( +- QcowDiskSync::new(file, disk_cfg.direct) ++ QcowDiskSync::new(file, disk_cfg.direct, disk_cfg.backing_files) + .map_err(DeviceManagerError::CreateQcowDiskSync)?, + ) as Box + } +diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs +index 5c11b3a..bba40f1 100644 +--- a/vmm/src/vm_config.rs ++++ b/vmm/src/vm_config.rs +@@ -227,6 +227,8 @@ pub struct DiskConfig { + pub serial: Option, + #[serde(default)] + pub queue_affinity: Option>, ++ #[serde(default)] ++ pub backing_files: bool, + } + + pub const DEFAULT_DISK_NUM_QUEUES: usize = 1; +-- +2.43.0 + diff --git a/SPECS/cloud-hypervisor-cvm/cloud-hypervisor-cvm.spec b/SPECS/cloud-hypervisor-cvm/cloud-hypervisor-cvm.spec index 35ae8a062c4..f8f55c5dbb0 100644 --- a/SPECS/cloud-hypervisor-cvm/cloud-hypervisor-cvm.spec +++ b/SPECS/cloud-hypervisor-cvm/cloud-hypervisor-cvm.spec @@ -5,7 +5,7 @@ Name: cloud-hypervisor-cvm Summary: Cloud Hypervisor CVM is an open source Virtual Machine Monitor (VMM) that enables running SEV SNP enabled VMs on top of MSHV using the IGVM file format as payload. Version: 38.0.72.2 -Release: 5%{?dist} +Release: 6%{?dist} License: ASL 2.0 OR BSD-3-clause Vendor: Microsoft Corporation Distribution: Mariner @@ -34,6 +34,7 @@ Patch0: upgrade-openssl-to-3.3.2-to-address-CVE-2024-6119.patch Patch1: 0001-hypervisor-mshv-Fix-panic-when-rejecting-extended-gu.patch Patch2: microsoft-cloud-hypervisor-6695.patch Patch3: CVE-2024-12797.patch +Patch4: CVE-2026-27211.patch Conflicts: cloud-hypervisor @@ -152,7 +153,10 @@ cargo build --release --target=%{rust_musl_target} %{cargo_pkg_feature_opts} %{c %license LICENSE-BSD-3-Clause %changelog -* Sun Feb 16 2024 Kanishk Bansal - 38.0.72.2-5 +* Thu Feb 27 2026 Akhila Guruju - 30.0.72.2-6 +- Patch CVE-2026-27211 + +* Fri Feb 16 2024 Kanishk Bansal - 38.0.72.2-5 - Address CVE-2024-12797 * Tue Oct 01 2024 Aurelien Bombo - 38.0.72.2-4