From 8c61286d67396ede174b14a977175642161a2a01 Mon Sep 17 00:00:00 2001 From: andre-braga Date: Mon, 10 Jun 2024 21:28:00 +0000 Subject: [PATCH] uefi: Add TryFrom u8 slice to DevicePathNode Adds the capability to convert a byte slice to a DevicePathNode. This will be used to convert a byte slice to a DevicePath in a followup PR, which allows easier interaction with the data returned from UEFI variable services. --- uefi/CHANGELOG.md | 2 +- uefi/src/proto/device_path/mod.rs | 42 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 70b95be05..1c1748b3b 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -11,7 +11,7 @@ - Added `table::{set_system_table, system_table_boot, system_table_runtime}`. This provides an initial API for global tables that do not require passing around a reference. -- Added `TryFrom<&[u8]>` for `DevicePathHeader`. +- Added `TryFrom<&[u8]>` for `DevicePathHeader` and `DevicePathNode`. - Added `ByteConversionError`. ## Changed diff --git a/uefi/src/proto/device_path/mod.rs b/uefi/src/proto/device_path/mod.rs index 6696bcce8..087440bb5 100644 --- a/uefi/src/proto/device_path/mod.rs +++ b/uefi/src/proto/device_path/mod.rs @@ -266,6 +266,19 @@ impl PartialEq for DevicePathNode { } } +impl<'a> TryFrom<&[u8]> for &'a DevicePathNode { + type Error = ByteConversionError; + + fn try_from(bytes: &[u8]) -> Result { + let dp = <&DevicePathHeader>::try_from(bytes)?; + if usize::from(dp.length) <= bytes.len() { + unsafe { Ok(DevicePathNode::from_ffi_ptr(bytes.as_ptr().cast())) } + } else { + Err(ByteConversionError::InvalidLength) + } + } +} + /// A single device path instance that ends with either an [`END_INSTANCE`] /// or [`END_ENTIRE`] node. Use [`DevicePath::instance_iter`] to get the /// path instances in a [`DevicePath`]. @@ -975,4 +988,33 @@ mod tests { let owned_dp_ref = &*owned_dp; assert_eq!(owned_dp_ref, dp) } + + #[test] + fn test_device_path_node_from_bytes() { + let mut raw_data = Vec::new(); + let node = [0xa0, 0xb0]; + let node_data = &[10, 11]; + + // Raw data is less than size of a [`DevicePathNode`]. + raw_data.push(node[0]); + assert!(<&DevicePathNode>::try_from(raw_data.as_slice()).is_err()); + + // Raw data is long enough to hold a [`DevicePathNode`]. + raw_data.push(node[1]); + raw_data.extend( + u16::try_from(mem::size_of::() + node_data.len()) + .unwrap() + .to_le_bytes(), + ); + raw_data.extend(node_data); + let dp = <&DevicePathNode>::try_from(raw_data.as_slice()).unwrap(); + + // Relevant assertions to verify the conversion is fine. + assert_eq!(mem::size_of_val(dp), 6); + check_node(dp, 0xa0, 0xb0, &[10, 11]); + + // [`DevicePathNode`] data length exceeds the raw_data slice. + raw_data[2] += 1; + assert!(<&DevicePathNode>::try_from(raw_data.as_slice()).is_err()); + } }