libfdt: Make unsafe API for DT cloning safe
The Fdt::copy_from_slice() was unsound as it allowed client code to
bypass the (safe) constructor (which validates the class invariant) and
provide arbitrary bytes that would then be available as a "safe" (but
not actually) &Fdt. Instead of marking that API unsafe (which it should
have been), rework it into a safe API taking a &Self, meaning that the
invariant has already been validated for the input.
Update callers to use the new API. In particular, note that this change
forces one of them to be marked unsafe (which is good!).
Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: I7d2d8ecb85c26f5644ca26330c057568a75656ce
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 770fdf0..e83fe5a 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -662,7 +662,9 @@
let info = parse_device_tree(fdt, vm_dtbo.as_deref())?;
- fdt.copy_from_slice(pvmfw_fdt_template::RAW).map_err(|e| {
+ // SAFETY: We trust that the template (hardcoded in our RO data) is a valid DT.
+ let fdt_template = unsafe { Fdt::unchecked_from_slice(pvmfw_fdt_template::RAW) };
+ fdt.clone_from(fdt_template).map_err(|e| {
error!("Failed to instantiate FDT from the template DT: {e}");
RebootReason::InvalidFdt
})?;
@@ -936,7 +938,7 @@
// SAFETY: on failure, the corrupted DT is restored using the backup.
if let Err(e) = unsafe { fdt.apply_overlay(overlay) } {
warn!("Failed to apply debug policy: {e}. Recovering...");
- fdt.copy_from_slice(backup_fdt.as_slice())?;
+ fdt.clone_from(backup_fdt)?;
// A successful restoration is considered success because an invalid debug policy
// shouldn't DOS the pvmfw
Ok(false)