Skip to content

Commit 0fd2c51

Browse files
Merge pull request #1201 from andre-braga/path
uefi: Add TryFrom u8 slice to DevicePath
2 parents 34e52a1 + 798797e commit 0fd2c51

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

uefi/CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
- Added `table::{set_system_table, system_table_boot, system_table_runtime}`.
1212
This provides an initial API for global tables that do not require passing
1313
around a reference.
14-
- Added `TryFrom<&[u8]>` for `DevicePathHeader` and `DevicePathNode`.
14+
- Added `TryFrom<&[u8]>` for `DevicePathHeader`, `DevicePathNode` and `DevicePath`.
1515
- Added `ByteConversionError`.
1616

1717
## Changed

uefi/src/proto/device_path/mod.rs

+62
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,35 @@ impl DevicePath {
396396
total_size_in_bytes
397397
}
398398

399+
/// Calculate the size in bytes of the entire `DevicePath` starting
400+
/// at `bytes`. This adds up each node's length, including the
401+
/// end-entire node.
402+
///
403+
/// # Errors
404+
///
405+
/// The [`ByteConversionError::InvalidLength`] error will be returned
406+
/// when the length of the given bytes slice cannot contain the full
407+
/// [`DevicePath`] represented by the slice.
408+
fn size_in_bytes_from_slice(mut bytes: &[u8]) -> Result<usize, ByteConversionError> {
409+
let max_size_in_bytes = bytes.len();
410+
let mut total_size_in_bytes: usize = 0;
411+
loop {
412+
let node = <&DevicePathNode>::try_from(bytes)?;
413+
let node_size_in_bytes = usize::from(node.length());
414+
total_size_in_bytes += node_size_in_bytes;
415+
// Length of last processed node extends past the bytes slice.
416+
if total_size_in_bytes > max_size_in_bytes {
417+
return Err(ByteConversionError::InvalidLength);
418+
}
419+
if node.is_end_entire() {
420+
break;
421+
}
422+
bytes = &bytes[node_size_in_bytes..];
423+
}
424+
425+
Ok(total_size_in_bytes)
426+
}
427+
399428
/// Create a [`DevicePath`] reference from an opaque pointer.
400429
///
401430
/// # Safety
@@ -487,6 +516,15 @@ impl PartialEq for DevicePath {
487516
}
488517
}
489518

519+
impl<'a> TryFrom<&[u8]> for &'a DevicePath {
520+
type Error = ByteConversionError;
521+
522+
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
523+
let len = DevicePath::size_in_bytes_from_slice(bytes)?;
524+
unsafe { Ok(&*ptr_meta::from_raw_parts(bytes.as_ptr().cast(), len)) }
525+
}
526+
}
527+
490528
#[cfg(feature = "alloc")]
491529
impl ToOwned for DevicePath {
492530
type Owned = Box<DevicePath>;
@@ -1016,4 +1054,28 @@ mod tests {
10161054
raw_data[2] += 1;
10171055
assert!(<&DevicePathNode>::try_from(raw_data.as_slice()).is_err());
10181056
}
1057+
1058+
#[test]
1059+
fn test_device_path_nodes_from_bytes() {
1060+
let raw_data = create_raw_device_path();
1061+
let dp = <&DevicePath>::try_from(raw_data.as_slice()).unwrap();
1062+
1063+
// Check that the size is the sum of the nodes' lengths.
1064+
assert_eq!(mem::size_of_val(dp), 6 + 8 + 4 + 6 + 8 + 4);
1065+
1066+
// Check the list's node iter.
1067+
let nodes: Vec<_> = dp.node_iter().collect();
1068+
check_node(nodes[0], 0xa0, 0xb0, &[10, 11]);
1069+
check_node(nodes[1], 0xa1, 0xb1, &[20, 21, 22, 23]);
1070+
check_node(
1071+
nodes[2],
1072+
DeviceType::END.0,
1073+
DeviceSubType::END_INSTANCE.0,
1074+
&[],
1075+
);
1076+
check_node(nodes[3], 0xa2, 0xb2, &[30, 31]);
1077+
check_node(nodes[4], 0xa3, 0xb3, &[40, 41, 42, 43]);
1078+
// The end-entire node is not returned by the iterator.
1079+
assert_eq!(nodes.len(), 5);
1080+
}
10191081
}

0 commit comments

Comments
 (0)