Skip to content

Commit 65155fa

Browse files
Fix memory leaks in DevicePathFromText
The methods of both DevicePathToText and DevicePathFromText return memory that is allocated internally by UEFI, so it needs to be freed on drop. DevicePathToText already does that correctly by returning a `PoolString`, but this was missed in DevicePathFromText, which just returns a reference. Fix by adding PoolDevicePath and PoolDevicePathNode structs, and return them from the corresponding methods of DevicePathFromText.
1 parent a651c18 commit 65155fa

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

uefi-test-runner/src/proto/device_path.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ pub fn test() {
3030
)
3131
.expect("Failed to open DevicePathFromText protocol");
3232

33+
// Test round-trip conversion from path to text and back.
34+
let device_path_string = device_path_to_text
35+
.convert_device_path_to_text(&device_path, DisplayOnly(false), AllowShortcuts(false))
36+
.unwrap();
37+
assert_eq!(
38+
*device_path_from_text
39+
.convert_text_to_device_path(&device_path_string)
40+
.unwrap(),
41+
*device_path
42+
);
43+
3344
for path in device_path.node_iter() {
3445
info!(
3546
"path: type={:?}, subtype={:?}, length={}",
@@ -47,7 +58,7 @@ pub fn test() {
4758
let convert = device_path_from_text
4859
.convert_text_to_device_node(text)
4960
.expect("Failed to convert text to device path");
50-
assert_eq!(path, convert);
61+
assert_eq!(*path, *convert);
5162
}
5263

5364
// Get the `LoadedImageDevicePath`. Verify it start with the same nodes as

uefi/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
# uefi - [Unreleased]
22

3+
## Added
4+
- Added `proto::device_path::PoolDevicePath` and
5+
`proto::device_path::PoolDevicePathNode`.
6+
37
## Changed
48
- MSRV increased to 1.81.
59
- `core::error::Error` impls are no longer gated by the `unstable` feature.
610
- Fixed missing checks in the `TryFrom` conversion from `&DevicePathNode` to
711
specific node types. The node type and subtype are now checked, and
812
`NodeConversionError::DifferentType` is returned if they do not match.
13+
- **Breaking:** Fixed memory leaks in `DevicePathFromText` protocol. The methods
14+
now return wrapper objects that free the device path / device path node on
15+
drop.
916

1017

1118
# uefi - 0.33.0 (2024-10-23)

uefi/src/proto/device_path/text.rs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,30 @@ impl Deref for PoolString {
6161
}
6262
}
6363

64+
/// Device path allocated from UEFI pool memory.
65+
#[derive(Debug)]
66+
pub struct PoolDevicePath(PoolAllocation);
67+
68+
impl Deref for PoolDevicePath {
69+
type Target = DevicePath;
70+
71+
fn deref(&self) -> &Self::Target {
72+
unsafe { DevicePath::from_ffi_ptr(self.0.as_ptr().as_ptr().cast()) }
73+
}
74+
}
75+
76+
/// Device path node allocated from UEFI pool memory.
77+
#[derive(Debug)]
78+
pub struct PoolDevicePathNode(PoolAllocation);
79+
80+
impl Deref for PoolDevicePathNode {
81+
type Target = DevicePathNode;
82+
83+
fn deref(&self) -> &Self::Target {
84+
unsafe { DevicePathNode::from_ffi_ptr(self.0.as_ptr().as_ptr().cast()) }
85+
}
86+
}
87+
6488
/// Device Path to Text protocol.
6589
///
6690
/// This protocol provides common utility functions for converting device
@@ -139,14 +163,12 @@ impl DevicePathFromText {
139163
pub fn convert_text_to_device_node(
140164
&self,
141165
text_device_node: &CStr16,
142-
) -> Result<&DevicePathNode> {
166+
) -> Result<PoolDevicePathNode> {
143167
unsafe {
144168
let ptr = (self.0.convert_text_to_device_node)(text_device_node.as_ptr().cast());
145-
if ptr.is_null() {
146-
Err(Status::OUT_OF_RESOURCES.into())
147-
} else {
148-
Ok(DevicePathNode::from_ffi_ptr(ptr.cast()))
149-
}
169+
NonNull::new(ptr.cast_mut())
170+
.map(|p| PoolDevicePathNode(PoolAllocation::new(p.cast())))
171+
.ok_or(Status::OUT_OF_RESOURCES.into())
150172
}
151173
}
152174

@@ -160,14 +182,12 @@ impl DevicePathFromText {
160182
/// memory for the conversion.
161183
///
162184
/// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES
163-
pub fn convert_text_to_device_path(&self, text_device_path: &CStr16) -> Result<&DevicePath> {
185+
pub fn convert_text_to_device_path(&self, text_device_path: &CStr16) -> Result<PoolDevicePath> {
164186
unsafe {
165187
let ptr = (self.0.convert_text_to_device_path)(text_device_path.as_ptr().cast());
166-
if ptr.is_null() {
167-
Err(Status::OUT_OF_RESOURCES.into())
168-
} else {
169-
Ok(DevicePath::from_ffi_ptr(ptr.cast()))
170-
}
188+
NonNull::new(ptr.cast_mut())
189+
.map(|p| PoolDevicePath(PoolAllocation::new(p.cast())))
190+
.ok_or(Status::OUT_OF_RESOURCES.into())
171191
}
172192
}
173193
}

0 commit comments

Comments
 (0)