pvmfw: Validate config header entries when Config::new()

This makes implicit assumptions explicit in one place and also helps to
remove unnecessary checks when getting entries.

Bug: N/A
Test: atest CustomPvmfwHostTestCases
Change-Id: Idad0ce1e827ae94bbdf6afba946a0375e199634f
diff --git a/pvmfw/src/config.rs b/pvmfw/src/config.rs
index 2451ec9..47a2492 100644
--- a/pvmfw/src/config.rs
+++ b/pvmfw/src/config.rs
@@ -19,6 +19,7 @@
 use core::num::NonZeroUsize;
 use core::ops::Range;
 use core::result;
+use core::slice;
 use log::{info, warn};
 use static_assertions::const_assert_eq;
 use vmbase::util::RangeExt;
@@ -54,6 +55,8 @@
     MissingEntry(Entry),
     /// Range described by entry does not fit within config data.
     EntryOutOfBounds(Entry, Range<usize>, Range<usize>),
+    /// Entries are in out of order
+    EntryOutOfOrder,
 }
 
 impl fmt::Display for Error {
@@ -71,6 +74,7 @@
                     "Entry {entry:?} out of bounds: {range:#x?} must be within range {limits:#x?}"
                 )
             }
+            Self::EntryOutOfOrder => write!(f, "Entries are out of order"),
         }
     }
 }
@@ -228,6 +232,7 @@
         // Ensure entries are in the body.
         let limits = header.body_lowest_bound()?..total_size;
         let mut ranges: [Option<NonEmptyRange>; Entry::COUNT] = [None; Entry::COUNT];
+        let mut last_end = 0;
         for entry in [Entry::Bcc, Entry::DebugPolicy, Entry::VmDtbo] {
             let Some(header_entry) = header_entries.get(entry as usize) else { continue };
             let entry_offset = header_entry.offset.try_into().unwrap();
@@ -238,44 +243,50 @@
                 return Err(Error::EntryOutOfBounds(entry, range, limits));
             }
 
+            if last_end > range.start {
+                return Err(Error::EntryOutOfOrder);
+            }
+            last_end = range.end;
+
             ranges[entry as usize] = NonEmptyRange::new(
                 entry_offset - limits.start, // is_within() validates safety of this.
                 entry_size,
             );
         }
+        // Ensures that BCC exists.
+        ranges[Entry::Bcc as usize].ok_or(Error::MissingEntry(Entry::Bcc))?;
 
         Ok(Self { body, ranges })
     }
 
     /// Get slice containing the platform BCC.
-    pub fn get_entries(&mut self) -> Result<(&mut [u8], Option<&mut [u8]>)> {
+    pub fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
         // This assumes that the blobs are in-order w.r.t. the entries.
-        let bcc_range = self.get_entry_range(Entry::Bcc).ok_or(Error::MissingEntry(Entry::Bcc))?;
+        let bcc_range = self.get_entry_range(Entry::Bcc);
         let dp_range = self.get_entry_range(Entry::DebugPolicy);
         let vm_dtbo_range = self.get_entry_range(Entry::VmDtbo);
         // TODO(b/291191157): Provision device assignment with this.
         if let Some(vm_dtbo_range) = vm_dtbo_range {
             info!("Found VM DTBO at {:?}", vm_dtbo_range);
         }
-        let bcc_start = bcc_range.start;
-        let bcc_end = bcc_range.len();
-        let (_, rest) = self.body.split_at_mut(bcc_start);
-        let (bcc, rest) = rest.split_at_mut(bcc_end);
 
-        let dp = if let Some(dp_range) = dp_range {
-            let dp_start = dp_range.start.checked_sub(bcc_range.end()).unwrap();
-            let dp_end = dp_range.len();
-            let (_, rest) = rest.split_at_mut(dp_start);
-            let (dp, _) = rest.split_at_mut(dp_end);
-            Some(dp)
-        } else {
-            None
-        };
-
-        Ok((bcc, dp))
+        // SAFETY: When instantiate, ranges are validated to be in the body range without
+        // overlapping.
+        unsafe {
+            let ptr = self.body.as_mut_ptr() as usize;
+            (
+                Self::from_raw_range_mut(ptr, bcc_range.unwrap()),
+                dp_range.map(|dp_range| Self::from_raw_range_mut(ptr, dp_range)),
+            )
+        }
     }
 
     fn get_entry_range(&self, entry: Entry) -> Option<NonEmptyRange> {
         self.ranges[entry as usize]
     }
+
+    unsafe fn from_raw_range_mut(ptr: usize, range: NonEmptyRange) -> &'a mut [u8] {
+        // SAFETY: The caller must ensure that the range is valid from ptr.
+        unsafe { slice::from_raw_parts_mut((ptr + range.start) as *mut u8, range.end()) }
+    }
 }
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index 3efa61e..9c929a9 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -207,10 +207,7 @@
         RebootReason::InvalidConfig
     })?;
 
-    let (bcc_slice, debug_policy) = appended.get_entries().map_err(|e| {
-        error!("Failed to obtained the config entries: {e}");
-        RebootReason::InvalidConfig
-    })?;
+    let (bcc_slice, debug_policy) = appended.get_entries();
 
     // Up to this point, we were using the built-in static (from .rodata) page tables.
     MEMORY.lock().replace(MemoryTracker::new(
@@ -430,10 +427,10 @@
         }
     }
 
-    fn get_entries(&mut self) -> config::Result<(&mut [u8], Option<&mut [u8]>)> {
+    fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
         match self {
             Self::Config(ref mut cfg) => cfg.get_entries(),
-            Self::LegacyBcc(ref mut bcc) => Ok((bcc, None)),
+            Self::LegacyBcc(ref mut bcc) => (bcc, None),
         }
     }
 }