Merge "pvmfw: Add support for /avf/untrusted" into main
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 311f467..146d012 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -59,6 +59,8 @@
InvalidCpuCount(usize),
/// Invalid VCpufreq Range.
InvalidVcpufreq(u64, u64),
+ /// Forbidden /avf/untrusted property.
+ ForbiddenUntrustedProp(&'static CStr),
}
impl fmt::Display for FdtValidationError {
@@ -68,6 +70,9 @@
Self::InvalidVcpufreq(addr, size) => {
write!(f, "Invalid vcpufreq region: ({addr:#x}, {size:#x})")
}
+ Self::ForbiddenUntrustedProp(name) => {
+ write!(f, "Forbidden /avf/untrusted property '{name:?}'")
+ }
}
}
}
@@ -420,6 +425,24 @@
Ok(())
}
+/// Reads the /avf/untrusted DT node, which the host can use to pass properties (no subnodes) to
+/// the guest that don't require being validated by pvmfw.
+fn parse_untrusted_props(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
+ let mut props = BTreeMap::new();
+ if let Some(node) = fdt.node(cstr!("/avf/untrusted"))? {
+ for property in node.properties()? {
+ let name = property.name()?;
+ let value = property.value()?;
+ props.insert(CString::from(name), value.to_vec());
+ }
+ if node.subnodes()?.next().is_some() {
+ warn!("Discarding unexpected /avf/untrusted subnodes.");
+ }
+ }
+
+ Ok(props)
+}
+
/// Read candidate properties' names from DT which could be overlaid
fn parse_vm_ref_dt(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
let mut property_map = BTreeMap::new();
@@ -436,6 +459,19 @@
Ok(property_map)
}
+fn validate_untrusted_props(props: &BTreeMap<CString, Vec<u8>>) -> Result<(), FdtValidationError> {
+ const FORBIDDEN_PROPS: &[&CStr] =
+ &[cstr!("compatible"), cstr!("linux,phandle"), cstr!("phandle")];
+
+ for name in FORBIDDEN_PROPS {
+ if props.contains_key(*name) {
+ return Err(FdtValidationError::ForbiddenUntrustedProp(name));
+ }
+ }
+
+ Ok(())
+}
+
/// Overlay VM reference DT into VM DT based on the props_info. Property is overlaid in vm_dt only
/// when it exists both in vm_ref_dt and props_info. If the values mismatch, it returns error.
fn validate_vm_ref_dt(
@@ -837,6 +873,23 @@
node.setprop_inplace(cstr!("interrupts"), value.as_bytes())
}
+fn patch_untrusted_props(fdt: &mut Fdt, props: &BTreeMap<CString, Vec<u8>>) -> libfdt::Result<()> {
+ let avf_node = if let Some(node) = fdt.node_mut(cstr!("/avf"))? {
+ node
+ } else {
+ fdt.root_mut()?.add_subnode(cstr!("avf"))?
+ };
+
+ // The node shouldn't already be present; if it is, return the error.
+ let mut node = avf_node.add_subnode(cstr!("untrusted"))?;
+
+ for (name, value) in props {
+ node.setprop(name, value)?;
+ }
+
+ Ok(())
+}
+
#[derive(Debug)]
struct VcpufreqInfo {
addr: u64,
@@ -864,6 +917,7 @@
serial_info: SerialInfo,
pub swiotlb_info: SwiotlbInfo,
device_assignment: Option<DeviceAssignmentInfo>,
+ untrusted_props: BTreeMap<CString, Vec<u8>>,
vm_ref_dt_props_info: BTreeMap<CString, Vec<u8>>,
vcpufreq_info: Option<VcpufreqInfo>,
}
@@ -1023,6 +1077,15 @@
None => None,
};
+ let untrusted_props = parse_untrusted_props(fdt).map_err(|e| {
+ error!("Failed to read untrusted properties: {e}");
+ RebootReason::InvalidFdt
+ })?;
+ validate_untrusted_props(&untrusted_props).map_err(|e| {
+ error!("Failed to validate untrusted properties: {e}");
+ RebootReason::InvalidFdt
+ })?;
+
let vm_ref_dt_props_info = parse_vm_ref_dt(fdt).map_err(|e| {
error!("Failed to read names of properties under /avf from DT: {e}");
RebootReason::InvalidFdt
@@ -1039,6 +1102,7 @@
serial_info,
swiotlb_info,
device_assignment,
+ untrusted_props,
vm_ref_dt_props_info,
vcpufreq_info,
})
@@ -1097,6 +1161,10 @@
RebootReason::InvalidFdt
})?;
}
+ patch_untrusted_props(fdt, &info.untrusted_props).map_err(|e| {
+ error!("Failed to patch untrusted properties: {e}");
+ RebootReason::InvalidFdt
+ })?;
Ok(())
}