Skip to content

Commit 8a28823

Browse files
committed
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.
1 parent 80c2137 commit 8a28823

File tree

1 file changed

+47
-11
lines changed

1 file changed

+47
-11
lines changed

multiboot2-header/src/header.rs

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,51 @@ impl<'a> Multiboot2Header<'a> {
6262
}
6363

6464
/// Find the header in a given slice.
65-
pub fn find_header(buffer: &[u8]) -> Option<(&[u8], u32)> {
65+
///
66+
/// If it succeeds, it returns a tuple consisting of the subslice containing
67+
/// just the header and the index of the header in the given slice.
68+
/// If it fails (either because the header is not properply 64-bit aligned
69+
/// or because it is truncated), it returns a [`BufError`].
70+
/// If there is no header, it returns `None`.
71+
pub fn find_header(buffer: &[u8]) -> Result<Option<(&[u8], u32)>, BufError> {
6672
// the magic is 32 bit aligned and inside the first 8192 bytes
6773
assert!(buffer.len() >= 8192);
68-
let mut chunks = buffer[0..8192].chunks_exact(4);
69-
let magic_index = match chunks.position(|vals| {
74+
let mut windows = buffer[0..8192].windows(4);
75+
let magic_index = match windows.position(|vals| {
7076
u32::from_le_bytes(vals.try_into().unwrap()) // yes, there's 4 bytes here
7177
== MULTIBOOT2_HEADER_MAGIC
7278
}) {
73-
Some(idx) => idx * 4,
74-
None => return None,
79+
Some(idx) => {
80+
if idx % 8 == 0 {
81+
idx
82+
} else {
83+
return Err(BufError::Unaligned);
84+
}
85+
}
86+
None => return Ok(None),
7587
};
76-
chunks.next(); // arch
77-
let header_length: usize = u32::from_le_bytes(chunks.next().unwrap().try_into().unwrap())
78-
.try_into()
79-
.unwrap();
80-
Some((
88+
// skip over rest of magic
89+
windows.next();
90+
windows.next();
91+
windows.next();
92+
// arch
93+
windows.next();
94+
windows.next();
95+
windows.next();
96+
windows.next();
97+
let header_length: usize = u32::from_le_bytes(
98+
windows
99+
.next()
100+
.ok_or(BufError::TooSmall)?
101+
.try_into()
102+
.unwrap(), // 4 bytes are a u32
103+
)
104+
.try_into()
105+
.unwrap();
106+
Ok(Some((
81107
&buffer[magic_index..magic_index + header_length],
82108
magic_index as u32,
83-
))
109+
)))
84110
}
85111

86112
/// Wrapper around [`Multiboot2BasicHeader::verify_checksum`].
@@ -181,6 +207,16 @@ impl<'a> Debug for Multiboot2Header<'a> {
181207
}
182208
}
183209

210+
/// Errors that can occur, when parsing a header from a slice.
211+
/// See [`Multiboot2Header::find_from_slice`].
212+
#[derive(Debug)]
213+
pub enum BufError {
214+
/// The header in the given slice is truncated.
215+
TooSmall,
216+
/// The header in the given slice is not properly 64-bit aligned.
217+
Unaligned,
218+
}
219+
184220
/// **Use this only if you know what you do. You probably want to use
185221
/// [`Multiboot2Header`] instead.**
186222
///

0 commit comments

Comments
 (0)