pvmfw: Clean up dangling references in __symbols__ Bug: 277993056 Test: atest libpvmfw.device_assignment.test Change-Id: I682868d173e516a52d3e5b09dfb11e31a7aad02f
diff --git a/pvmfw/src/device_assignment.rs b/pvmfw/src/device_assignment.rs index e427710..2c47f9e 100644 --- a/pvmfw/src/device_assignment.rs +++ b/pvmfw/src/device_assignment.rs
@@ -294,6 +294,26 @@ .map_or(false, |name| name == b"__overlay__") } +fn filter_dangling_symbols(fdt: &mut Fdt) -> Result<()> { + if let Some(symbols) = fdt.symbols()? { + let mut removed = vec![]; + for prop in symbols.properties()? { + let path = CStr::from_bytes_with_nul(prop.value()?) + .map_err(|_| DeviceAssignmentError::Internal)?; + if fdt.node(path)?.is_none() { + let name = prop.name()?; + removed.push(CString::from(name)); + } + } + + let mut symbols = fdt.symbols_mut()?.unwrap(); + for name in removed { + symbols.nop_property(&name)?; + } + } + Ok(()) +} + impl AsRef<Fdt> for VmDtbo { fn as_ref(&self) -> &Fdt { &self.0 @@ -744,7 +764,8 @@ device.patch(fdt, &pviommu_phandles)?; } - Ok(()) + // Removes any dangling references in __symbols__ (e.g. removed pvIOMMUs) + filter_dangling_symbols(fdt) } } @@ -1020,6 +1041,39 @@ } #[test] + fn device_info_patch_no_pviommus() { + let mut fdt_data = fs::read(FDT_WITHOUT_IOMMUS_FILE_PATH).unwrap(); + let mut vm_dtbo_data = fs::read(VM_DTBO_FILE_PATH).unwrap(); + let mut data = vec![0_u8; fdt_data.len() + vm_dtbo_data.len()]; + let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap(); + let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap(); + let platform_dt = Fdt::create_empty_tree(data.as_mut_slice()).unwrap(); + + let hypervisor = MockHypervisor { + mmio_tokens: [((0x9, 0xFF), 0x300)].into(), + iommu_tokens: BTreeMap::new(), + }; + let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor).unwrap().unwrap(); + device_info.filter(vm_dtbo).unwrap(); + + // SAFETY: Damaged VM DTBO wouldn't be used after this unsafe block. + unsafe { + platform_dt.apply_overlay(vm_dtbo.as_mut()).unwrap(); + } + device_info.patch(platform_dt).unwrap(); + + let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu")).unwrap(); + assert_eq!(None, compatible); + + if let Some(symbols) = platform_dt.symbols().unwrap() { + for prop in symbols.properties().unwrap() { + let path = CStr::from_bytes_with_nul(prop.value().unwrap()).unwrap(); + assert_ne!(None, platform_dt.node(path).unwrap()); + } + } + } + + #[test] fn device_info_overlay_iommu() { let mut fdt_data = fs::read(FDT_FILE_PATH).unwrap(); let mut vm_dtbo_data = fs::read(VM_DTBO_FILE_PATH).unwrap();