Quellcode durchsuchen

multiboot2-header: Make find_header return a Result

This should make the function easier to use:
If the header is not properly aligned or cut off, the function
previously just returned None or might have even panicked.
Niklas Sombert vor 1 Jahr
Ursprung
Commit
a190e48478
1 geänderte Dateien mit 47 neuen und 11 gelöschten Zeilen
  1. 47 11
      multiboot2-header/src/header.rs

+ 47 - 11
multiboot2-header/src/header.rs

@@ -62,25 +62,51 @@ impl<'a> Multiboot2Header<'a> {
     }
 
     /// Find the header in a given slice.
-    pub fn find_header(buffer: &[u8]) -> Option<(&[u8], u32)> {
+    ///
+    /// If it succeeds, it returns a tuple consisting of the subslice containing
+    /// just the header and the index of the header in the given slice.
+    /// If it fails (either because the header is not properply 64-bit aligned
+    /// or because it is truncated), it returns a [`BufError`].
+    /// If there is no header, it returns `None`.
+    pub fn find_header(buffer: &[u8]) -> Result<Option<(&[u8], u32)>, BufError> {
         // the magic is 32 bit aligned and inside the first 8192 bytes
         assert!(buffer.len() >= 8192);
-        let mut chunks = buffer[0..8192].chunks_exact(4);
-        let magic_index = match chunks.position(|vals| {
+        let mut windows = buffer[0..8192].windows(4);
+        let magic_index = match windows.position(|vals| {
             u32::from_le_bytes(vals.try_into().unwrap()) // yes, there's 4 bytes here
             == MULTIBOOT2_HEADER_MAGIC
         }) {
-            Some(idx) => idx * 4,
-            None => return None,
+            Some(idx) => {
+                if idx % 8 == 0 {
+                    idx
+                } else {
+                    return Err(BufError::Unaligned);
+                }
+            }
+            None => return Ok(None),
         };
-        chunks.next(); // arch
-        let header_length: usize = u32::from_le_bytes(chunks.next().unwrap().try_into().unwrap())
-            .try_into()
-            .unwrap();
-        Some((
+        // skip over rest of magic
+        windows.next();
+        windows.next();
+        windows.next();
+        // arch
+        windows.next();
+        windows.next();
+        windows.next();
+        windows.next();
+        let header_length: usize = u32::from_le_bytes(
+            windows
+                .next()
+                .ok_or(BufError::TooSmall)?
+                .try_into()
+                .unwrap(), // 4 bytes are a u32
+        )
+        .try_into()
+        .unwrap();
+        Ok(Some((
             &buffer[magic_index..magic_index + header_length],
             magic_index as u32,
-        ))
+        )))
     }
 
     /// Wrapper around [`Multiboot2BasicHeader::verify_checksum`].
@@ -181,6 +207,16 @@ impl<'a> Debug for Multiboot2Header<'a> {
     }
 }
 
+/// Errors that can occur when parsing a header from a slice.
+/// See [`Multiboot2Header::find_header`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum BufError {
+    /// The header in the given slice is truncated.
+    TooSmall,
+    /// The header in the given slice is not properly 64-bit aligned.
+    Unaligned,
+}
+
 /// **Use this only if you know what you do. You probably want to use
 /// [`Multiboot2Header`] instead.**
 ///