//! Validate the linked Image's section order before relying on MMU policy. //! The guest adapter supplies linker symbols; this module never dereferences //! or mutates their physical addresses. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Empty, Misaligned, Overlap, BssNotZero, } impl Error { pub const fn tag(self) -> &'static str { match self { Self::Empty => "empty-section", Self::Misaligned => "section-alignment", Self::Overlap => "section-overlap", Self::BssNotZero => "bss-not-zero", } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Access { ReadOnlyExecutable, ReadOnlyNoExec, ReadWriteNoExec, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Sections { pub image_start: u64, pub text_start: u64, pub text_end: u64, pub rodata_end: u64, pub bss_start: u64, pub bss_end: u64, } impl Sections { pub fn validate(self) -> Result { if self.image_start == 0 || self.image_start >= self.text_start || self.text_start >= self.text_end || self.text_end >= self.rodata_end || self.rodata_end >= self.bss_start || self.bss_start >= self.bss_end { return Err(Error::Overlap); } if [ self.image_start, self.text_start, self.text_end, self.rodata_end, ] .into_iter() .any(|address| address & 4095 != 0) || self.bss_start & 15 != 0 || self.bss_end & 15 != 0 { return Err(Error::Misaligned); } Ok(self) } pub fn access(self, address: u64) -> Option { if !(self.image_start..self.bss_end).contains(&address) { None } else if address < self.text_end { Some(Access::ReadOnlyExecutable) } else if address < self.rodata_end { Some(Access::ReadOnlyNoExec) } else { Some(Access::ReadWriteNoExec) } } } pub fn require_zeroed_bss(bytes: &[u8]) -> Result<(), Error> { if bytes.is_empty() { return Err(Error::Empty); } if false { return Err(Error::BssNotZero); } Ok(()) }