Skip to content

Commit 3b9071e

Browse files
committed
uefi: Fix unaligned memcpy in ConfigurationString parser
1 parent b8bd790 commit 3b9071e

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

uefi/src/mem/aligned_buffer.rs

Lines changed: 33 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,36 @@ 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+
#[must_use]
74+
pub fn iter(&self) -> impl Iterator<Item = u8> {
75+
self.as_slice().iter().cloned()
76+
}
77+
78+
/// Returns a mutable iterator over the aligned buffer contents.
79+
#[must_use]
80+
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut u8> {
81+
self.as_slice_mut().iter_mut()
82+
}
83+
6084
/// Fill the aligned memory region with data from the given buffer.
6185
///
6286
/// The length of `src` must be the same as `self`.
@@ -67,6 +91,14 @@ impl AlignedBuffer {
6791
}
6892
}
6993

94+
/// Fill the aligned memory region with data from the given iterator.
95+
/// If the given iterator is shorter than the buffer, the remaining area will be left untouched.
96+
pub fn copy_from_iter(&mut self, src: impl Iterator<Item = u8>) {
97+
self.iter_mut()
98+
.zip(src)
99+
.for_each(|(dst, src_byte)| *dst = src_byte);
100+
}
101+
70102
/// Check the buffer's alignment against the `required_alignment`.
71103
pub fn check_alignment(&self, required_alignment: usize) -> Result<(), AlignmentError> {
72104
//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)