1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use core::cmp::{max, min};
16 use core::mem::size_of;
17 use fastboot::CommandError;
18 
19 use static_assertions::const_assert;
20 use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref};
21 
22 // TODO(b/331854173): Switch to use bindgen for the following type definitions once
23 // system/core/libsparse is added to repo checkout.
24 
25 const HEADER_MAGIC: u32 = 0xED26FF3A;
26 const CHUNK_TYPE_RAW: u16 = 0xCAC1;
27 const CHUNK_TYPE_FILL: u16 = 0xCAC2;
28 const CHUNK_TYPE_DONT_CARE: u16 = 0xCAC3;
29 const CHUNK_TYPE_CRC32: u16 = 0xCAC4;
30 
31 const SPARSE_HEADER_MAJOR_VER: u16 = 1;
32 const SPARSE_HEADER_MINOR_VER: u16 = 0;
33 
34 #[repr(C)]
35 #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
36 pub struct SparseHeader {
37     pub magic: u32,
38     pub major_version: u16,
39     pub minor_version: u16,
40     pub file_hdr_sz: u16,
41     pub chunk_hdr_sz: u16,
42     pub blk_sz: u32,
43     pub total_blks: u32,
44     pub total_chunks: u32,
45     pub image_checksum: u32,
46 }
47 
48 #[repr(C)]
49 #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
50 pub struct ChunkHeader {
51     pub chunk_type: u16,
52     pub reserved1: u16,
53     pub chunk_sz: u32,
54     pub total_sz: u32,
55 }
56 
57 const ERR_ARITHMETIC_OVERFLOW: &str = "Arithmetic Overflow";
58 const ERR_IMAGE_SIZE: &str = "Bad image. Invalid image size";
59 
60 /// Checks if a sparse image is valid and returns the sparse header.
is_sparse_image(sparse_img: &[u8]) -> Result<SparseHeader, CommandError>61 pub fn is_sparse_image(sparse_img: &[u8]) -> Result<SparseHeader, CommandError> {
62     let sparse_header: SparseHeader = copy_from(sparse_img)?;
63     if sparse_header.magic != HEADER_MAGIC {
64         return Err("Sparse magic mismatch".into());
65     } else if sparse_header.major_version != SPARSE_HEADER_MAJOR_VER {
66         return Err("Sparse major version mismatch".into());
67     } else if sparse_header.minor_version != SPARSE_HEADER_MINOR_VER {
68         return Err("Sparse minor version mismatch".into());
69     }
70     Ok(sparse_header)
71 }
72 
73 /// `FillInfo` is derived from a sparse chunk and contains information whether to fill a value or
74 /// skip for a number of blocks.
75 ///
76 /// Context and uses:
77 ///
78 /// When writing fill chunks from a sparse image, it is usually better to write a larger buffer
79 /// with the filled value instead of a single u32 at a time. However, separately maintaining a fill
80 /// buffer can be inconvenient for the caller. Therefore, we use a strategy that re-uses the input
81 /// buffer for fill buffer.
82 ///
83 /// The idea is to write the sparse image in two passes. In the first pass, we only write non-fill
84 /// chunks. For each sparse chunk, we create a `FillInfo` and append it from the beginning of the
85 /// input buffer. For fill chunks, `FillInfo::fill_blocks` and
86 /// `FillInfo::fill_value_or_skip_blocks` are set to the chunk size and fill value. For others,
87 /// `FillInfo::fill_blocks` will be set to 0 and `FillInfo::fill_value_or_skip_blocks` will be set
88 /// to the chunk size instead to represent number of blocks to skip. The second pass writes the
89 /// fill chunk according to `FillInfo`.
90 ///
91 /// Because a sparse chunk is at least 12 bytes, whereas `FillInfo` is 8 bytes, at the end of the
92 /// first pass, we are guaranteed to have at least 1/3 of the input buffer free to use as fill
93 /// buffer.
94 #[repr(C, packed)]
95 #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
96 struct FillInfo {
97     // Number of blocks to fill.
98     pub fill_blocks: u32,
99     // If `fill_blocks` is None, this field represents the number of blocks to skip.
100     // Otherwise, it represents the fill value.
101     pub fill_value_or_skip_blocks: u32,
102 }
103 
104 impl FillInfo {
105     /// Creates an instance that represents filling a number of blocks.
new_fill(blocks: u32, value: u32) -> Self106     fn new_fill(blocks: u32, value: u32) -> Self {
107         assert_ne!(blocks, 0);
108         Self { fill_blocks: blocks, fill_value_or_skip_blocks: value }
109     }
110 
111     /// Creates an instance that represents skipping a number of blocks.
new_skip(blocks: u32) -> Self112     fn new_skip(blocks: u32) -> Self {
113         Self { fill_blocks: 0, fill_value_or_skip_blocks: blocks }
114     }
115 
116     // Returns (blocks, None) for the skip case or (blocks, Some(value)) for the fill case.
get_blocks_and_value(&self) -> (u32, Option<u32>)117     fn get_blocks_and_value(&self) -> (u32, Option<u32>) {
118         match self.fill_blocks {
119             0 => (self.fill_value_or_skip_blocks, None),
120             v => (v, Some(self.fill_value_or_skip_blocks)),
121         }
122     }
123 }
124 
125 const_assert!(size_of::<FillInfo>() < size_of::<ChunkHeader>());
126 
127 /// Write a sparse image in `sparse_img`.
128 ///
129 /// # Args
130 //
131 /// * `sparse_img`: The input buffer containing the sparse image. The API modifes input buffer for
132 ///   internal optimization.
133 /// * `write`: A closure as the writer. It takes an offset and a `&mut [u8]` as the write data.
134 ///
135 /// # Returns
136 ///
137 /// Returns the total number of bytes written, including don't care chunks.
write_sparse_image<F>(sparse_img: &mut [u8], mut write: F) -> Result<u64, CommandError> where F: FnMut(u64, &mut [u8]) -> Result<(), CommandError>,138 pub fn write_sparse_image<F>(sparse_img: &mut [u8], mut write: F) -> Result<u64, CommandError>
139 where
140     F: FnMut(u64, &mut [u8]) -> Result<(), CommandError>,
141 {
142     let sparse_header: SparseHeader = is_sparse_image(sparse_img)?;
143     let mut curr: usize = size_of::<SparseHeader>();
144     let mut write_offset = 0u64;
145 
146     // First pass. Writes non-fill chunk and constructs `FillInfo`.
147     let mut fill_off = 0usize;
148     for _ in 0..sparse_header.total_chunks {
149         let header: ChunkHeader = copy_from(&mut sparse_img[curr..])?;
150         let payload = &mut sparse_img[curr + size_of::<ChunkHeader>()..];
151         let payload_sz = u64_mul(header.chunk_sz, sparse_header.blk_sz)?;
152         let mut fill = FillInfo::new_skip(header.chunk_sz);
153         match header.chunk_type {
154             CHUNK_TYPE_RAW => write(write_offset, get_mut(payload, 0, to_usize(payload_sz)?)?)?,
155             CHUNK_TYPE_FILL if header.chunk_sz != 0 => {
156                 let fill_val = u32::from_le_bytes(get_mut(payload, 0, 4)?.try_into().unwrap());
157                 fill = FillInfo::new_fill(header.chunk_sz, fill_val);
158             }
159             CHUNK_TYPE_DONT_CARE | CHUNK_TYPE_CRC32 => {}
160             _ => return Err("Invalid Chunk Type".into()),
161         };
162         write_offset = u64_add(write_offset, payload_sz)?;
163         sparse_img[fill_off..][..size_of::<FillInfo>()].clone_from_slice(fill.as_bytes());
164         fill_off = usize_add(fill_off, size_of::<FillInfo>())?;
165         curr = usize_add(curr, header.total_sz)?;
166     }
167     let total = write_offset;
168 
169     // Second pass. Writes fill chunks.
170     // Use all reamining buffer as fill buffer.
171     let (fill_infos, fill_buffer) = sparse_img.split_at_mut(fill_off);
172     let mut fill_buffer = FillBuffer { curr_val: None, curr_size: 0, buffer: fill_buffer };
173     let fill_infos = Ref::<_, [FillInfo]>::new_slice(fill_infos).unwrap().into_slice();
174     write_offset = 0;
175     for ele in fill_infos {
176         match ele.get_blocks_and_value() {
177             (blks, None) => {
178                 write_offset = u64_add(write_offset, u64_mul(blks, sparse_header.blk_sz)?)?;
179             }
180             (blks, Some(v)) => {
181                 let sz = u64_mul(blks, sparse_header.blk_sz)?;
182                 let buffer = fill_buffer.get(v, sz)?;
183                 let buffer_len = to_u64(buffer.len())?;
184                 let end = u64_add(write_offset, sz)?;
185                 while write_offset < end {
186                     let to_write = min(buffer_len, end - write_offset);
187                     write(write_offset, &mut buffer[..to_usize(to_write).unwrap()])?;
188                     write_offset += to_write;
189                 }
190             }
191         }
192     }
193     Ok(total)
194 }
195 
196 /// `FillUnit` is a packed C struct wrapping a u32. It is mainly used for filling a buffer of
197 /// arbitrary alignment with a u32 value.
198 #[repr(C, packed)]
199 #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
200 struct FillUnit(u32);
201 
202 /// `FillBuffer` manages a buffer and provides API for making a fill buffer with the given value.
203 struct FillBuffer<'a> {
204     curr_val: Option<u32>,
205     curr_size: usize,
206     buffer: &'a mut [u8],
207 }
208 
209 impl FillBuffer<'_> {
210     /// Get a buffer up to `size` number of bytes filled with `val`.
get(&mut self, val: u32, size: u64) -> Result<&mut [u8], CommandError>211     fn get(&mut self, val: u32, size: u64) -> Result<&mut [u8], CommandError> {
212         let aligned_len = self.buffer.len() - (self.buffer.len() % size_of::<u32>());
213         let size: usize = min(to_u64(aligned_len)?, size).try_into().unwrap();
214         if Some(val) != self.curr_val {
215             self.curr_size = 0;
216             self.curr_val = Some(val);
217         }
218         let gap = max(self.curr_size, size) - self.curr_size;
219         let to_fill = &mut self.buffer[self.curr_size..][..gap];
220         Ref::<_, [FillUnit]>::new_slice(to_fill).unwrap().into_mut_slice().fill(FillUnit(val));
221         self.curr_size += gap;
222         Ok(&mut self.buffer[..size])
223     }
224 }
225 
226 /// A helper to check and get a mutable sub slice.
get_mut<L: TryInto<usize>, R: TryInto<usize>>( bytes: &mut [u8], start: L, end: R, ) -> Result<&mut [u8], CommandError>227 fn get_mut<L: TryInto<usize>, R: TryInto<usize>>(
228     bytes: &mut [u8],
229     start: L,
230     end: R,
231 ) -> Result<&mut [u8], CommandError> {
232     bytes.get_mut(to_usize(start)?..to_usize(end)?).ok_or(ERR_IMAGE_SIZE.into())
233 }
234 
235 /// A helper to check and get a sub slice.
get<L: TryInto<usize>, R: TryInto<usize>>( bytes: &[u8], start: L, end: R, ) -> Result<&[u8], CommandError>236 fn get<L: TryInto<usize>, R: TryInto<usize>>(
237     bytes: &[u8],
238     start: L,
239     end: R,
240 ) -> Result<&[u8], CommandError> {
241     bytes.get(to_usize(start)?..to_usize(end)?).ok_or(ERR_IMAGE_SIZE.into())
242 }
243 
244 /// A helper to return a copy of a zerocopy object from bytes.
copy_from<T: AsBytes + FromBytes + Default>(bytes: &[u8]) -> Result<T, CommandError>245 fn copy_from<T: AsBytes + FromBytes + Default>(bytes: &[u8]) -> Result<T, CommandError> {
246     let mut res: T = Default::default();
247     res.as_bytes_mut().clone_from_slice(get(bytes, 0, size_of::<T>())?);
248     Ok(res)
249 }
250 
251 /// Checks and converts an integer into usize.
to_usize<T: TryInto<usize>>(val: T) -> Result<usize, CommandError>252 fn to_usize<T: TryInto<usize>>(val: T) -> Result<usize, CommandError> {
253     Ok(val.try_into().map_err(|_| ERR_ARITHMETIC_OVERFLOW)?)
254 }
255 
256 /// Adds two usize convertible numbers and checks overflow.
usize_add<L: TryInto<usize>, R: TryInto<usize>>(lhs: L, rhs: R) -> Result<usize, CommandError>257 fn usize_add<L: TryInto<usize>, R: TryInto<usize>>(lhs: L, rhs: R) -> Result<usize, CommandError> {
258     Ok(to_usize(lhs)?.checked_add(to_usize(rhs)?).ok_or(ERR_ARITHMETIC_OVERFLOW)?)
259 }
260 
261 /// Checks and converts an integer into u64
to_u64<T: TryInto<u64>>(val: T) -> Result<u64, CommandError>262 fn to_u64<T: TryInto<u64>>(val: T) -> Result<u64, CommandError> {
263     Ok(val.try_into().map_err(|_| ERR_ARITHMETIC_OVERFLOW)?)
264 }
265 
266 /// Adds two u64 convertible numbers and checks overflow.
u64_add<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, CommandError>267 fn u64_add<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, CommandError> {
268     Ok(to_u64(lhs)?.checked_add(to_u64(rhs)?).ok_or(ERR_ARITHMETIC_OVERFLOW)?)
269 }
270 
271 /// Multiplies two u64 convertible numbers and checks overflow.
u64_mul<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, CommandError>272 fn u64_mul<L: TryInto<u64>, R: TryInto<u64>>(lhs: L, rhs: R) -> Result<u64, CommandError> {
273     Ok(to_u64(lhs)?.checked_mul(to_u64(rhs)?).ok_or(ERR_ARITHMETIC_OVERFLOW)?)
274 }
275 
276 #[cfg(test)]
277 mod test {
278     use super::*;
279 
280     #[test]
test_sparse_write()281     fn test_sparse_write() {
282         let raw = include_bytes!("../../testdata/sparse_test_raw.bin");
283         let sparse = include_bytes!("../../testdata/sparse_test.bin");
284         // Gives a larger output buffer.
285         let mut out = vec![0u8; 2 * raw.len()];
286         assert_eq!(
287             write_sparse_image(&mut sparse.to_vec()[..], |off, data| {
288                 out[off.try_into().unwrap()..][..data.len()].clone_from_slice(data);
289                 Ok(())
290             })
291             .unwrap(),
292             raw.len().try_into().unwrap()
293         );
294         assert_eq!(out[..raw.len()].to_vec(), raw);
295     }
296 
297     #[test]
test_sparse_write_non_default_block_size()298     fn test_sparse_write_non_default_block_size() {
299         let raw = include_bytes!("../../testdata/sparse_test_raw.bin");
300         let sparse = include_bytes!("../../testdata/sparse_test_blk1024.bin");
301         // Gives a larger output buffer.
302         let mut out = vec![0u8; 2 * raw.len()];
303         assert_eq!(
304             write_sparse_image(&mut sparse.to_vec()[..], |off, data| {
305                 out[off.try_into().unwrap()..][..data.len()].clone_from_slice(data);
306                 Ok(())
307             })
308             .unwrap(),
309             raw.len().try_into().unwrap()
310         );
311         assert_eq!(out[..raw.len()].to_vec(), raw);
312     }
313 
314     /// A helper to copy a zerocopy object into a buffer
copy_to<T: AsBytes + FromBytes>(val: &T, bytes: &mut [u8])315     fn copy_to<T: AsBytes + FromBytes>(val: &T, bytes: &mut [u8]) {
316         bytes[..size_of::<T>()].clone_from_slice(val.as_bytes());
317     }
318 
319     #[test]
test_sparse_invalid_magic()320     fn test_sparse_invalid_magic() {
321         let mut sparse = include_bytes!("../../testdata/sparse_test.bin").to_vec();
322         let mut sparse_header: SparseHeader = copy_from(&sparse[..]).unwrap();
323         sparse_header.magic = 0;
324         copy_to(&sparse_header, &mut sparse[..]);
325         assert!(write_sparse_image(&mut sparse[..], |_, _| panic!()).is_err());
326     }
327 
328     #[test]
test_sparse_invalid_major_version()329     fn test_sparse_invalid_major_version() {
330         let mut sparse = include_bytes!("../../testdata/sparse_test.bin").to_vec();
331         let mut sparse_header: SparseHeader = copy_from(&sparse[..]).unwrap();
332         sparse_header.major_version = SPARSE_HEADER_MAJOR_VER + 1;
333         copy_to(&sparse_header, &mut sparse[..]);
334         assert!(write_sparse_image(&mut sparse[..], |_, _| panic!()).is_err());
335     }
336 
337     #[test]
test_sparse_invalid_minor_version()338     fn test_sparse_invalid_minor_version() {
339         let mut sparse = include_bytes!("../../testdata/sparse_test.bin").to_vec();
340         let mut sparse_header: SparseHeader = copy_from(&sparse[..]).unwrap();
341         sparse_header.minor_version = SPARSE_HEADER_MINOR_VER + 1;
342         copy_to(&sparse_header, &mut sparse[..]);
343         assert!(write_sparse_image(&mut sparse[..], |_, _| panic!()).is_err());
344     }
345 }
346