pvmfw: debug policy application failure is recoverable
If pvmfw fails to apply the debug policy, the original fdt is recovered
from the backup.
In this change also moves apply_debug_policy into modify_for_next_stage,
so that modification to the fdt after the verification is done in one
place.
Finally, error codes that are specific to debug policy are replaced with
the original errors from libfdt because the former don't give much
detail information than the other.
Bug: 275132866
Bug: 275306568
Test: forcibly modify a bit in debug_policy inside pvmfw and see if the
VM boots (without applying it). Flashing an invalid debug_policy was not
an option for the test because then ABL would reject it and doesn't pass
it to pvmfw at all.
Change-Id: I1c40967087449deb89a9698a87109fc16e588b70
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 7d88455..d15eaba 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -22,6 +22,7 @@
use crate::memory::MAX_ADDR;
use crate::RebootReason;
use alloc::ffi::CString;
+use alloc::vec::Vec;
use core::cmp::max;
use core::cmp::min;
use core::ffi::CStr;
@@ -36,6 +37,7 @@
use libfdt::FdtNode;
use log::debug;
use log::error;
+use log::info;
use tinyvec::ArrayVec;
/// Extract from /config the address range containing the pre-loaded kernel. Absence of /config is
@@ -672,6 +674,7 @@
bcc: &[u8],
new_instance: bool,
strict_boot: bool,
+ debug_policy: Option<&mut [u8]>,
) -> libfdt::Result<()> {
fdt.unpack()?;
@@ -680,6 +683,13 @@
set_or_clear_chosen_flag(fdt, cstr!("avf,strict-boot"), strict_boot)?;
set_or_clear_chosen_flag(fdt, cstr!("avf,new-instance"), new_instance)?;
+ if let Some(debug_policy) = debug_policy {
+ apply_debug_policy(fdt, debug_policy)?;
+ info!("Debug policy applied.");
+ } else {
+ info!("No debug policy found.");
+ }
+
fdt.pack()?;
Ok(())
@@ -712,3 +722,26 @@
Ok(())
}
+
+fn apply_debug_policy(fdt: &mut Fdt, debug_policy: &mut [u8]) -> libfdt::Result<()> {
+ let backup_fdt = Vec::from(fdt.as_slice());
+
+ let overlay = match Fdt::from_mut_slice(debug_policy) {
+ Ok(overlay) => overlay,
+ Err(e) => {
+ info!("Corrupted debug policy found: {e}. Not applying.");
+ return Ok(());
+ }
+ };
+ let backup_overlay = Vec::from(overlay.as_slice());
+
+ // SAFETY - on failure, the corrupted fdts are discarded and are restored using the backups.
+ if let Err(e) = unsafe { fdt.apply_overlay(overlay) } {
+ error!("Failed to apply debug policy: {e}. Recovering...");
+ fdt.copy_from_slice(backup_fdt.as_slice())?;
+ overlay.copy_from_slice(backup_overlay.as_slice())?;
+ // A successful restoration is considered success because an invalid debug policy
+ // shouldn't DOS the pvmfw
+ }
+ Ok(())
+}