Skip to content

Commit 9b5cb8c

Browse files
committed
uefi: Fix unaligned memcpy in ConfigurationString parser
1 parent b8bd790 commit 9b5cb8c

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

uefi/src/mem/aligned_buffer.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
use alloc::alloc::{Layout, LayoutError, alloc, dealloc};
44
use core::error::Error;
5-
use core::fmt;
65
use core::ptr::NonNull;
6+
use core::{fmt, slice};
77

88
/// Helper class to maintain the lifetime of a memory region allocated with a non-standard alignment.
99
/// Facilitates RAII to properly deallocate when lifetime of the object ends.
@@ -51,12 +51,34 @@ impl AlignedBuffer {
5151
self.ptr.as_ptr()
5252
}
5353

54+
/// Get the underlying memory region as immutable slice.
55+
#[must_use]
56+
pub const fn as_slice(&self) -> &[u8] {
57+
unsafe { slice::from_raw_parts(self.ptr(), self.size()) }
58+
}
59+
60+
/// Get the underlying memory region as mutable slice.
61+
#[must_use]
62+
pub const fn as_slice_mut(&mut self) -> &mut [u8] {
63+
unsafe { slice::from_raw_parts_mut(self.ptr_mut(), self.size()) }
64+
}
65+
5466
/// Get the size of the aligned memory region managed by this instance.
5567
#[must_use]
5668
pub const fn size(&self) -> usize {
5769
self.layout.size()
5870
}
5971

72+
/// Returns an iterator over the aligned buffer contents.
73+
pub fn iter(&self) -> impl Iterator<Item = u8> {
74+
self.as_slice().iter().cloned()
75+
}
76+
77+
/// Returns a mutable iterator over the aligned buffer contents.
78+
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut u8> {
79+
self.as_slice_mut().iter_mut()
80+
}
81+
6082
/// Fill the aligned memory region with data from the given buffer.
6183
///
6284
/// The length of `src` must be the same as `self`.
@@ -67,6 +89,14 @@ impl AlignedBuffer {
6789
}
6890
}
6991

92+
/// Fill the aligned memory region with data from the given iterator.
93+
/// If the given iterator is shorter than the buffer, the remaining area will be left untouched.
94+
pub fn copy_from_iter(&mut self, src: impl Iterator<Item = u8>) {
95+
self.iter_mut()
96+
.zip(src)
97+
.for_each(|(dst, src_byte)| *dst = src_byte);
98+
}
99+
70100
/// Check the buffer's alignment against the `required_alignment`.
71101
pub fn check_alignment(&self, required_alignment: usize) -> Result<(), AlignmentError> {
72102
//TODO: use bfr.addr() when it's available

uefi/src/proto/hii/config_str.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use core::slice;
99
use core::str::{self, FromStr};
1010
use uguid::Guid;
1111

12+
use crate::mem::AlignedBuffer;
1213
use crate::proto::device_path::DevicePath;
1314
use crate::{CStr16, Char16};
1415

@@ -169,11 +170,15 @@ impl ConfigurationString {
169170
if data.len() % 2 != 0 {
170171
return None;
171172
}
172-
let mut data: Vec<_> = Self::parse_bytes_from_hex(data).collect();
173-
data.chunks_exact_mut(2).for_each(|c| c.swap(0, 1));
174-
data.extend_from_slice(&[0, 0]);
173+
let size_bytes = data.len() / 2 + 2; // includes \0 terminator
174+
let size_chars = size_bytes / 2;
175+
let mut bfr = AlignedBuffer::from_size_align(size_bytes, 2).ok()?;
176+
bfr.copy_from_iter(Self::parse_bytes_from_hex(data).chain([0, 0]));
177+
bfr.as_slice_mut()
178+
.chunks_exact_mut(2)
179+
.for_each(|c| c.swap(0, 1));
175180
let data: &[Char16] =
176-
unsafe { slice::from_raw_parts(data.as_slice().as_ptr().cast(), data.len() / 2) };
181+
unsafe { slice::from_raw_parts(bfr.as_slice().as_ptr().cast(), size_chars) };
177182
Some(CStr16::from_char16_with_nul(data).ok()?.to_string())
178183
}
179184

0 commit comments

Comments
 (0)