From c0e65264e588cbd2af240c5c11aa1442d5f305c2 Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson Date: Mon, 11 Nov 2024 19:38:17 -0500 Subject: [PATCH] sparse: Allow parsing files with unknown fields The official AOSP implementation does, so we should too. This allows unpacking Samsung's sparse images, which have an extra 4 bytes in both the file header and chunk headers. Signed-off-by: Andrew Gunnerson --- avbroot/src/format/sparse.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/avbroot/src/format/sparse.rs b/avbroot/src/format/sparse.rs index ed22d5c..c5864c0 100644 --- a/avbroot/src/format/sparse.rs +++ b/avbroot/src/format/sparse.rs @@ -14,6 +14,8 @@ use thiserror::Error; use zerocopy::{byteorder::little_endian, FromZeros, IntoBytes}; use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned}; +use crate::stream::ReadDiscardExt; + /// Magic value for [`RawHeader::magic`]. const HEADER_MAGIC: u32 = 0xed26ff3a; @@ -108,15 +110,17 @@ impl RawHeader { ))); } - if self.file_hdr_sz.get() != mem::size_of::() as u16 { + if self.file_hdr_sz.get() < mem::size_of::() as u16 { return Err(Error::Header(format!( - "Invalid file header size: {}", + "Invalid file header size: {} < {}", self.file_hdr_sz.get(), + mem::size_of::(), ))); - } else if self.chunk_hdr_sz.get() != mem::size_of::() as u16 { + } else if self.chunk_hdr_sz.get() < mem::size_of::() as u16 { return Err(Error::Header(format!( - "Invalid chunk header size: {}", + "Invalid chunk header size: {} < {}", self.chunk_hdr_sz.get(), + mem::size_of::(), ))); } @@ -129,6 +133,14 @@ impl RawHeader { Ok(()) } + + fn excess_raw_header_bytes(&self) -> u16 { + self.file_hdr_sz.get() - mem::size_of::() as u16 + } + + fn excess_raw_chunk_bytes(&self) -> u16 { + self.chunk_hdr_sz.get() - mem::size_of::() as u16 + } } /// Raw on-disk layout for the chunk header. @@ -180,7 +192,7 @@ impl RawChunk { }; data_size - .checked_add(mem::size_of::() as u32) + .checked_add(header.chunk_hdr_sz.into()) .ok_or_else(|| Error::Chunk(index, format!("Data size too large: {data_size}"))) } @@ -662,6 +674,8 @@ impl SparseReader { header.validate()?; + inner.read_discard(header.excess_raw_header_bytes().into())?; + Ok(Self { inner, seek: None, @@ -724,6 +738,9 @@ impl SparseReader { raw_chunk.validate(self.chunk, &self.header, self.block)?; + self.inner + .read_discard(self.header.excess_raw_chunk_bytes().into())?; + let data: ChunkData; match raw_chunk.chunk_type.get() {