Skip to content

Commit e32026b

Browse files
committed
multiboot2: more memory safety in TagIter
1 parent ac8be5a commit e32026b

File tree

2 files changed

+26
-11
lines changed

2 files changed

+26
-11
lines changed

multiboot2/src/lib.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -464,10 +464,9 @@ impl BootInformation<'_> {
464464
.map(|tag| tag.cast_tag::<TagT>())
465465
}
466466

467+
/// Returns an iterator over all tags.
467468
fn tags(&self) -> TagIter {
468-
// The first tag starts 8 bytes after the begin of the boot info header
469-
let ptr = core::ptr::addr_of!(self.0.tags).cast();
470-
TagIter::new(ptr)
469+
TagIter::new(&self.0.tags)
471470
}
472471
}
473472

multiboot2/src/tag_type.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -377,17 +377,25 @@ impl StructAsBytes for EndTag {
377377
}
378378
}
379379

380+
/// Iterates the MBI's tags from the first tag to the end tag.
380381
#[derive(Clone, Debug)]
381382
pub struct TagIter<'a> {
383+
/// Pointer to the next tag. Updated in each iteration.
382384
pub current: *const Tag,
383-
phantom: PhantomData<&'a Tag>,
385+
/// The pointer right after the MBI. Used for additional bounds checking.
386+
end_ptr_exclusive: *const u8,
387+
/// Lifetime capture of the MBI's memory.
388+
_mem: PhantomData<&'a ()>,
384389
}
385390

386391
impl<'a> TagIter<'a> {
387-
pub fn new(first: *const Tag) -> Self {
392+
/// Creates a new iterator
393+
pub fn new(mem: &'a [u8]) -> Self {
394+
assert_eq!(mem.as_ptr().align_offset(8), 0);
388395
TagIter {
389-
current: first,
390-
phantom: PhantomData,
396+
current: mem.as_ptr().cast(),
397+
end_ptr_exclusive: unsafe { mem.as_ptr().add(mem.len()) },
398+
_mem: PhantomData,
391399
}
392400
}
393401
}
@@ -396,17 +404,25 @@ impl<'a> Iterator for TagIter<'a> {
396404
type Item = &'a Tag;
397405

398406
fn next(&mut self) -> Option<&'a Tag> {
399-
match unsafe { &*self.current } {
407+
// This never failed so far. But better be safe.
408+
assert!(self.current.cast::<u8>() < self.end_ptr_exclusive);
409+
410+
let tag = unsafe { &*self.current };
411+
match tag {
400412
&Tag {
401413
// END-Tag
402414
typ: TagTypeId(0),
403415
size: 8,
404416
} => None, // end tag
405417
tag => {
418+
// We return the tag and update self.current already to the next
419+
// tag.
420+
421+
// next pointer (rounded up to 8-byte alignment)
422+
let ptr_offset = (tag.size as usize + 7) & !7;
423+
406424
// go to next tag
407-
let mut tag_addr = self.current as usize;
408-
tag_addr += ((tag.size + 7) & !7) as usize; //align at 8 byte
409-
self.current = tag_addr as *const _;
425+
self.current = unsafe { self.current.cast::<u8>().add(ptr_offset).cast::<Tag>() };
410426

411427
Some(tag)
412428
}

0 commit comments

Comments
 (0)