pvmfw: Read kernel/initrd ranges from untrusted DT
Stop relying on the output of the DT sanitization for configuring the
memory region and ranges for the kernel and ramdisk as those will be
validated by the MemoryTracker anyway. This will enable moving the
sanitization to main(), to perform it with more function-level inputs.
Bug: 377276983
Test: atest com.android.pvmfw.test.DebugPolicyHostTests
Change-Id: Id7f24fc6952dcc508aee04da04db9ed15b921036
diff --git a/guest/pvmfw/src/fdt.rs b/guest/pvmfw/src/fdt.rs
index 027f163..4a7546a 100644
--- a/guest/pvmfw/src/fdt.rs
+++ b/guest/pvmfw/src/fdt.rs
@@ -83,7 +83,7 @@
/// Extract from /config the address range containing the pre-loaded kernel. Absence of /config is
/// not an error.
-fn read_kernel_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
+pub fn read_kernel_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
let addr = cstr!("kernel-address");
let size = cstr!("kernel-size");
@@ -101,7 +101,7 @@
/// Extract from /chosen the address range containing the pre-loaded ramdisk. Absence is not an
/// error as there can be initrd-less VM.
-fn read_initrd_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
+pub fn read_initrd_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
let start = cstr!("linux,initrd-start");
let end = cstr!("linux,initrd-end");
@@ -989,7 +989,6 @@
#[derive(Debug)]
pub struct DeviceTreeInfo {
- pub kernel_range: Option<Range<usize>>,
pub initrd_range: Option<Range<usize>>,
pub memory_range: Range<usize>,
bootargs: Option<CString>,
@@ -1015,15 +1014,10 @@
}
pub fn sanitize_device_tree(
- fdt: &mut [u8],
+ fdt: &mut Fdt,
vm_dtbo: Option<&mut [u8]>,
vm_ref_dt: Option<&[u8]>,
) -> Result<DeviceTreeInfo, RebootReason> {
- let fdt = Fdt::from_mut_slice(fdt).map_err(|e| {
- error!("Failed to load FDT: {e}");
- RebootReason::InvalidFdt
- })?;
-
let vm_dtbo = match vm_dtbo {
Some(vm_dtbo) => Some(VmDtbo::from_mut_slice(vm_dtbo).map_err(|e| {
error!("Failed to load VM DTBO: {e}");
@@ -1086,11 +1080,6 @@
}
fn parse_device_tree(fdt: &Fdt, vm_dtbo: Option<&VmDtbo>) -> Result<DeviceTreeInfo, RebootReason> {
- let kernel_range = read_kernel_range_from(fdt).map_err(|e| {
- error!("Failed to read kernel range from DT: {e}");
- RebootReason::InvalidFdt
- })?;
-
let initrd_range = read_initrd_range_from(fdt).map_err(|e| {
error!("Failed to read initrd range from DT: {e}");
RebootReason::InvalidFdt
@@ -1194,7 +1183,6 @@
})?;
Ok(DeviceTreeInfo {
- kernel_range,
initrd_range,
memory_range,
bootargs,
diff --git a/guest/pvmfw/src/memory.rs b/guest/pvmfw/src/memory.rs
index 35bfd3a..e51a730 100644
--- a/guest/pvmfw/src/memory.rs
+++ b/guest/pvmfw/src/memory.rs
@@ -15,7 +15,7 @@
//! Low-level allocation and tracking of main memory.
use crate::entry::RebootReason;
-use crate::fdt;
+use crate::fdt::{read_initrd_range_from, read_kernel_range_from, sanitize_device_tree};
use core::num::NonZeroUsize;
use core::slice;
use log::debug;
@@ -51,44 +51,39 @@
})?;
// SAFETY: map_data validated the range to be in main memory, mapped, and not overlap.
- let fdt = unsafe { slice::from_raw_parts_mut(fdt as *mut u8, fdt_size.into()) };
-
- let info = fdt::sanitize_device_tree(fdt, vm_dtbo, vm_ref_dt)?;
- let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
- error!("Failed to load sanitized FDT: {e}");
+ let untrusted_fdt = unsafe { slice::from_raw_parts_mut(fdt as *mut u8, fdt_size.into()) };
+ let untrusted_fdt = libfdt::Fdt::from_mut_slice(untrusted_fdt).map_err(|e| {
+ error!("Failed to load input FDT: {e}");
RebootReason::InvalidFdt
})?;
- debug!("Fdt passed validation!");
- let memory_range = info.memory_range;
+ let memory_range = untrusted_fdt.first_memory_range().map_err(|e| {
+ error!("Failed to read memory range from DT: {e}");
+ RebootReason::InvalidFdt
+ })?;
debug!("Resizing MemoryTracker to range {memory_range:#x?}");
resize_available_memory(&memory_range).map_err(|e| {
error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
RebootReason::InvalidFdt
})?;
- init_shared_pool(info.swiotlb_info.fixed_range()).map_err(|e| {
- error!("Failed to initialize shared pool: {e}");
- RebootReason::InternalError
+ let kernel_range = read_kernel_range_from(untrusted_fdt).map_err(|e| {
+ error!("Failed to read kernel range: {e}");
+ RebootReason::InvalidFdt
})?;
-
- let (kernel_start, kernel_size) = if let Some(r) = info.kernel_range {
- let size = r.len().try_into().map_err(|_| {
- error!("Invalid kernel size: {:#x}", r.len());
- RebootReason::InternalError
- })?;
- (r.start, size)
+ let (kernel_start, kernel_size) = if let Some(r) = kernel_range {
+ (r.start, r.len())
} else if cfg!(feature = "legacy") {
warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
- let size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
- error!("Invalid kernel size: {kernel_size:#x}");
- RebootReason::InvalidPayload
- })?;
- (kernel, size)
+ (kernel, kernel_size)
} else {
error!("Failed to locate the kernel from the DT");
return Err(RebootReason::InvalidPayload);
};
+ let kernel_size = kernel_size.try_into().map_err(|_| {
+ error!("Invalid kernel size: {kernel_size:#x}");
+ RebootReason::InvalidPayload
+ })?;
map_rodata(kernel_start, kernel_size).map_err(|e| {
error!("Failed to map kernel range: {e}");
@@ -99,7 +94,11 @@
// SAFETY: map_rodata validated the range to be in main memory, mapped, and not overlap.
let kernel = unsafe { slice::from_raw_parts(kernel, kernel_size.into()) };
- let ramdisk = if let Some(r) = info.initrd_range {
+ let initrd_range = read_initrd_range_from(untrusted_fdt).map_err(|e| {
+ error!("Failed to read initrd range: {e}");
+ RebootReason::InvalidFdt
+ })?;
+ let ramdisk = if let Some(r) = initrd_range {
debug!("Located ramdisk at {r:?}");
let ramdisk_size = r.len().try_into().map_err(|_| {
error!("Invalid ramdisk size: {:#x}", r.len());
@@ -118,6 +117,15 @@
None
};
+ let info = sanitize_device_tree(untrusted_fdt, vm_dtbo, vm_ref_dt)?;
+ debug!("Fdt passed validation!");
+ let fdt = untrusted_fdt;
+
+ init_shared_pool(info.swiotlb_info.fixed_range()).map_err(|e| {
+ error!("Failed to initialize shared pool: {e}");
+ RebootReason::InternalError
+ })?;
+
Ok(Self { fdt, kernel, ramdisk })
}
}