From 9650d6429667938a01b41a19e6de32f8f36b1aab Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 25 Apr 2024 11:52:58 +1000 Subject: [PATCH] pod: add slice_from_all_bytes{_mut} (#672) Also convert some code to use it. --- src/pod.rs | 52 ++++++++++++++++++++++++++++++++++++----- src/read/elf/section.rs | 29 ++++++++--------------- src/read/elf/segment.rs | 9 ++++--- src/read/pe/file.rs | 15 +++--------- 4 files changed, 63 insertions(+), 42 deletions(-) diff --git a/src/pod.rs b/src/pod.rs index 8a25b98e..2907e1e0 100644 --- a/src/pod.rs +++ b/src/pod.rs @@ -21,9 +21,11 @@ type Result = result::Result; /// - have no padding pub unsafe trait Pod: Copy + 'static {} -/// Cast a byte slice to a `Pod` type. +/// Cast the head of a byte slice to a `Pod` type. /// -/// Returns the type and the tail of the slice. +/// Returns the type and the tail of the byte slice. +/// +/// Returns an error if the byte slice is too short or the alignment is invalid. #[inline] pub fn from_bytes(data: &[u8]) -> Result<(&T, &[u8])> { let size = mem::size_of::(); @@ -39,9 +41,11 @@ pub fn from_bytes(data: &[u8]) -> Result<(&T, &[u8])> { Ok((val, tail)) } -/// Cast a mutable byte slice to a `Pod` type. +/// Cast the head of a mutable byte slice to a `Pod` type. +/// +/// Returns the type and the tail of the byte slice. /// -/// Returns the type and the tail of the slice. +/// Returns an error if the byte slice is too short or the alignment is invalid. #[inline] pub fn from_bytes_mut(data: &mut [u8]) -> Result<(&mut T, &mut [u8])> { let size = mem::size_of::(); @@ -60,9 +64,11 @@ pub fn from_bytes_mut(data: &mut [u8]) -> Result<(&mut T, &mut [u8])> { Ok((val, tail)) } -/// Cast a byte slice to a slice of a `Pod` type. +/// Cast the head of a byte slice to a slice of a `Pod` type. /// /// Returns the type slice and the tail of the byte slice. +/// +/// Returns an error if the byte slice is too short or the alignment is invalid. #[inline] pub fn slice_from_bytes(data: &[u8], count: usize) -> Result<(&[T], &[u8])> { let size = count.checked_mul(mem::size_of::()).ok_or(())?; @@ -78,9 +84,11 @@ pub fn slice_from_bytes(data: &[u8], count: usize) -> Result<(&[T], &[u8 Ok((slice, tail)) } -/// Cast a mutable byte slice to a slice of a `Pod` type. +/// Cast the head of a mutable byte slice to a slice of a `Pod` type. /// /// Returns the type slice and the tail of the byte slice. +/// +/// Returns an error if the byte slice is too short or the alignment is invalid. #[inline] pub fn slice_from_bytes_mut( data: &mut [u8], @@ -102,6 +110,38 @@ pub fn slice_from_bytes_mut( Ok((slice, tail)) } +/// Cast all of a byte slice to a slice of a `Pod` type. +/// +/// Returns the type slice. +/// +/// Returns an error if the size of the byte slice is not an exact multiple +/// of the type size, or the alignment is invalid. +#[inline] +pub fn slice_from_all_bytes(data: &[u8]) -> Result<&[T]> { + let count = data.len() / mem::size_of::(); + let (slice, tail) = slice_from_bytes(data, count)?; + if !tail.is_empty() { + return Err(()); + } + Ok(slice) +} + +/// Cast all of a byte slice to a slice of a `Pod` type. +/// +/// Returns the type slice. +/// +/// Returns an error if the size of the byte slice is not an exact multiple +/// of the type size, or the alignment is invalid. +#[inline] +pub fn slice_from_all_bytes_mut(data: &mut [u8]) -> Result<&mut [T]> { + let count = data.len() / mem::size_of::(); + let (slice, tail) = slice_from_bytes_mut(data, count)?; + if !tail.is_empty() { + return Err(()); + } + Ok(slice) +} + /// Cast a `Pod` type to a byte slice. #[inline] pub fn bytes_of(val: &T) -> &[u8] { diff --git a/src/read/elf/section.rs b/src/read/elf/section.rs index 5b7e8491..e0380eb9 100644 --- a/src/read/elf/section.rs +++ b/src/read/elf/section.rs @@ -1,12 +1,12 @@ use core::fmt::Debug; -use core::{iter, mem, slice, str}; +use core::{iter, slice, str}; use crate::elf; use crate::endian::{self, Endianness, U32Bytes}; -use crate::pod::Pod; +use crate::pod::{self, Pod}; use crate::read::{ - self, Bytes, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection, - ReadError, ReadRef, RelocationMap, SectionFlags, SectionIndex, SectionKind, StringTable, + self, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection, ReadError, + ReadRef, RelocationMap, SectionFlags, SectionIndex, SectionKind, StringTable, }; use super::{ @@ -671,8 +671,7 @@ pub trait SectionHeader: Debug + Pod { endian: Self::Endian, data: R, ) -> read::Result<&'data [T]> { - let mut data = self.data(endian, data).map(Bytes)?; - data.read_slice(data.len() / mem::size_of::()) + pod::slice_from_all_bytes(self.data(endian, data)?) .read_error("Invalid ELF section size or offset") } @@ -816,19 +815,11 @@ pub trait SectionHeader: Debug + Pod { if self.sh_type(endian) != elf::SHT_GROUP { return Ok(None); } - let mut data = self - .data(endian, data) - .read_error("Invalid ELF group section offset or size") - .map(Bytes)?; - let flag = data - .read::>() - .read_error("Invalid ELF group section offset or size")? - .get(endian); - let count = data.len() / mem::size_of::>(); - let sections = data - .read_slice(count) - .read_error("Invalid ELF group section offset or size")?; - Ok(Some((flag, sections))) + let msg = "Invalid ELF group section offset or size"; + let data = self.data(endian, data).read_error(msg)?; + let (flag, data) = pod::from_bytes::>(data).read_error(msg)?; + let sections = pod::slice_from_all_bytes(data).read_error(msg)?; + Ok(Some((flag.get(endian), sections))) } /// Return the header of a SysV hash section. diff --git a/src/read/elf/segment.rs b/src/read/elf/segment.rs index b5b740fa..f0c16186 100644 --- a/src/read/elf/segment.rs +++ b/src/read/elf/segment.rs @@ -1,10 +1,10 @@ use core::fmt::Debug; -use core::{mem, slice, str}; +use core::{slice, str}; use crate::elf; use crate::endian::{self, Endianness}; -use crate::pod::Pod; -use crate::read::{self, Bytes, ObjectSegment, ReadError, ReadRef, SegmentFlags}; +use crate::pod::{self, Pod}; +use crate::read::{self, ObjectSegment, ReadError, ReadRef, SegmentFlags}; use super::{ElfFile, FileHeader, NoteIterator}; @@ -180,8 +180,7 @@ pub trait ProgramHeader: Debug + Pod { endian: Self::Endian, data: R, ) -> Result<&'data [T], ()> { - let mut data = self.data(endian, data).map(Bytes)?; - data.read_slice(data.len() / mem::size_of::()) + pod::slice_from_all_bytes(self.data(endian, data)?) } /// Return the segment data in the given virtual address range diff --git a/src/read/pe/file.rs b/src/read/pe/file.rs index dec46ad1..2e9d4462 100644 --- a/src/read/pe/file.rs +++ b/src/read/pe/file.rs @@ -6,7 +6,7 @@ use core::convert::TryInto; use crate::endian::{LittleEndian as LE, U32}; use crate::pe; -use crate::pod::Pod; +use crate::pod::{self, Pod}; use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable}; use crate::read::{ self, Architecture, ByteString, Bytes, CodeView, ComdatKind, Error, Export, FileFlags, Import, @@ -317,17 +317,8 @@ where Some(data_dir) => data_dir, None => return Ok(None), }; - let debug_data = data_dir.data(self.data, &self.common.sections).map(Bytes)?; - let debug_data_size = data_dir.size.get(LE) as usize; - - let count = debug_data_size / mem::size_of::(); - let rem = debug_data_size % mem::size_of::(); - if rem != 0 || count < 1 { - return Err(Error("Invalid PE debug dir size")); - } - - let debug_dirs = debug_data - .read_slice_at::(0, count) + let debug_data = data_dir.data(self.data, &self.common.sections)?; + let debug_dirs = pod::slice_from_all_bytes::(debug_data) .read_error("Invalid PE debug dir size")?; for debug_dir in debug_dirs {