Skip to content

Commit 5eb0a14

Browse files
Mark open_protocol as unsafe
1 parent af3f533 commit 5eb0a14

File tree

3 files changed

+73
-68
lines changed

3 files changed

+73
-68
lines changed

CHANGELOG.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
### Changed
1919

2020
- Marked `BootServices::handle_protocol` as `unsafe`. (This method is
21-
also deprecated -- use `open_protocol` instead.)
21+
also deprecated -- use `open_protocol_exclusive` or `open_protocol` instead.)
2222
- Deprecated `BootServices::locate_protocol` and marked it `unsafe`. Use
2323
`BootServices::get_handle_for_protocol` and
24-
`BootServices::open_protocol` instead.
24+
`BootServices::open_protocol_exclusive` (or
25+
`BootServices::open_protocol`) instead.
2526
- renamed feature `ignore-logger-errors` to `panic-on-logger-errors` so that it is
2627
additive. It is now a default feature.
2728

src/table/boot.rs

+57-55
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,22 @@ static IMAGE_HANDLE: GlobalImageHandle = GlobalImageHandle {
4343
/// # Accessing protocols
4444
///
4545
/// Protocols can be opened using several methods of `BootServices`. Most
46-
/// commonly, [`open_protocol`] should be used. This returns a
46+
/// commonly, [`open_protocol_exclusive`] should be used. This ensures that
47+
/// nothing else can use the protocol until it is closed, and returns a
4748
/// [`ScopedProtocol`] that takes care of closing the protocol when it is
48-
/// dropped. If the protocol is opened in [`Exclusive`] mode, UEFI ensures that
49-
/// nothing else can use the protocol until it is closed.
49+
/// dropped.
5050
///
5151
/// Other methods for opening protocols:
5252
///
53+
/// * [`open_protocol`]
5354
/// * [`get_image_file_system`]
5455
/// * [`handle_protocol`]
5556
/// * [`locate_protocol`]
5657
///
5758
/// For protocol definitions, see the [`proto`] module.
5859
///
5960
/// [`proto`]: crate::proto
60-
/// [`Exclusive`]: OpenProtocolAttributes::Exclusive
61+
/// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive
6162
/// [`open_protocol`]: BootServices::open_protocol
6263
/// [`get_image_file_system`]: BootServices::get_image_file_system
6364
/// [`locate_protocol`]: BootServices::locate_protocol
@@ -623,7 +624,7 @@ impl BootServices {
623624
/// based on the protocol GUID.
624625
///
625626
/// It is recommended that all new drivers and applications use
626-
/// [`open_protocol`] instead of `handle_protocol`.
627+
/// [`open_protocol_exclusive`] or [`open_protocol`] instead of `handle_protocol`.
627628
///
628629
/// UEFI protocols are neither thread-safe nor reentrant, but the firmware
629630
/// provides no mechanism to protect against concurrent usage. Such
@@ -635,10 +636,14 @@ impl BootServices {
635636
/// This method is unsafe because the handle database is not
636637
/// notified that the handle and protocol are in use; there is no
637638
/// guarantee that they will remain valid for the duration of their
638-
/// use. Use [`open_protocol`] instead.
639+
/// use. Use [`open_protocol_exclusive`] if possible, otherwise use
640+
/// [`open_protocol`].
639641
///
640642
/// [`open_protocol`]: BootServices::open_protocol
641-
#[deprecated(note = "it is recommended to use `open_protocol` instead")]
643+
/// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive
644+
#[deprecated(
645+
note = "it is recommended to use `open_protocol_exclusive` or `open_protocol` instead"
646+
)]
642647
pub unsafe fn handle_protocol<P: ProtocolPointer + ?Sized>(
643648
&self,
644649
handle: Handle,
@@ -737,14 +742,7 @@ impl BootServices {
737742
/// # let boot_services: &BootServices = get_fake_val();
738743
/// # let image_handle: Handle = get_fake_val();
739744
/// let handle = boot_services.get_handle_for_protocol::<DevicePathToText>()?;
740-
/// let device_path_to_text = boot_services.open_protocol::<DevicePathToText>(
741-
/// OpenProtocolParams {
742-
/// handle,
743-
/// agent: image_handle,
744-
/// controller: None,
745-
/// },
746-
/// OpenProtocolAttributes::Exclusive,
747-
/// )?;
745+
/// let device_path_to_text = boot_services.open_protocol_exclusive::<DevicePathToText>(handle)?;
748746
/// # Ok(())
749747
/// # }
750748
/// ```
@@ -963,11 +961,14 @@ impl BootServices {
963961

964962
/// Open a protocol interface for a handle.
965963
///
964+
/// See also [`open_protocol_exclusive`], which provides a safe
965+
/// subset of this functionality.
966+
///
966967
/// This function attempts to get the protocol implementation of a
967968
/// handle, based on the protocol GUID. It is an extended version of
968969
/// [`handle_protocol`]. It is recommended that all
969-
/// new drivers and applications use `open_protocol` instead of
970-
/// `handle_protocol`.
970+
/// new drivers and applications use `open_protocol_exclusive` or
971+
/// `open_protocol` instead of `handle_protocol`.
971972
///
972973
/// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for
973974
/// details of the input parameters.
@@ -980,8 +981,19 @@ impl BootServices {
980981
/// protections must be implemented by user-level code, for example via a
981982
/// global `HashSet`.
982983
///
984+
/// # Safety
985+
///
986+
/// This function is unsafe because it can be used to open a
987+
/// protocol in ways that don't get tracked by the UEFI
988+
/// implementation. This could allow the protocol to be removed from
989+
/// a handle, or for the handle to be deleted entirely, while a
990+
/// reference to the protocol is still active. The caller is
991+
/// responsible for ensuring that the handle and protocol remain
992+
/// valid until the `ScopedProtocol` is dropped.
993+
///
983994
/// [`handle_protocol`]: BootServices::handle_protocol
984-
pub fn open_protocol<P: ProtocolPointer + ?Sized>(
995+
/// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive
996+
pub unsafe fn open_protocol<P: ProtocolPointer + ?Sized>(
985997
&self,
986998
params: OpenProtocolParams,
987999
attributes: OpenProtocolAttributes,
@@ -995,7 +1007,7 @@ impl BootServices {
9951007
params.controller,
9961008
attributes as u32,
9971009
)
998-
.into_with_val(|| unsafe {
1010+
.into_with_val(|| {
9991011
let interface = P::mut_ptr_from_ffi(interface) as *const UnsafeCell<P>;
10001012

10011013
#[allow(deprecated)]
@@ -1017,14 +1029,19 @@ impl BootServices {
10171029
&self,
10181030
handle: Handle,
10191031
) -> Result<ScopedProtocol<P>> {
1020-
self.open_protocol::<P>(
1021-
OpenProtocolParams {
1022-
handle,
1023-
agent: self.image_handle(),
1024-
controller: None,
1025-
},
1026-
OpenProtocolAttributes::Exclusive,
1027-
)
1032+
// Safety: opening in exclusive mode with the correct agent
1033+
// handle set ensures that the protocol cannot be modified or
1034+
// removed while it is open, so this usage is safe.
1035+
unsafe {
1036+
self.open_protocol::<P>(
1037+
OpenProtocolParams {
1038+
handle,
1039+
agent: self.image_handle(),
1040+
controller: None,
1041+
},
1042+
OpenProtocolAttributes::Exclusive,
1043+
)
1044+
}
10281045
}
10291046

10301047
/// Test whether a handle supports a protocol.
@@ -1099,9 +1116,15 @@ impl BootServices {
10991116
/// This method is unsafe because the handle database is not
11001117
/// notified that the handle and protocol are in use; there is no
11011118
/// guarantee that they will remain valid for the duration of their
1102-
/// use. Use [`BootServices::get_handle_for_protocol`] and
1103-
/// [`BootServices::open_protocol`] instead.
1104-
#[deprecated(note = "it is recommended to use `open_protocol` instead")]
1119+
/// use. Use [`get_handle_for_protocol`] and either
1120+
/// [`open_protocol_exclusive`] or [`open_protocol`] instead.
1121+
///
1122+
/// [`get_handle_for_protocol`]: BootServices::get_handle_for_protocol
1123+
/// [`open_protocol`]: BootServices::open_protocol
1124+
/// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive
1125+
#[deprecated(
1126+
note = "it is recommended to use `open_protocol_exclusive` or `open_protocol` instead"
1127+
)]
11051128
pub unsafe fn locate_protocol<P: ProtocolPointer + ?Sized>(&self) -> Result<&UnsafeCell<P>> {
11061129
let mut ptr = ptr::null_mut();
11071130
(self.locate_protocol)(&P::GUID, ptr::null_mut(), &mut ptr).into_with_val(|| {
@@ -1166,34 +1189,13 @@ impl BootServices {
11661189
&self,
11671190
image_handle: Handle,
11681191
) -> Result<ScopedProtocol<SimpleFileSystem>> {
1169-
let loaded_image = self.open_protocol::<LoadedImage>(
1170-
OpenProtocolParams {
1171-
handle: image_handle,
1172-
agent: image_handle,
1173-
controller: None,
1174-
},
1175-
OpenProtocolAttributes::Exclusive,
1176-
)?;
1177-
1178-
let device_path = self.open_protocol::<DevicePath>(
1179-
OpenProtocolParams {
1180-
handle: loaded_image.device(),
1181-
agent: image_handle,
1182-
controller: None,
1183-
},
1184-
OpenProtocolAttributes::Exclusive,
1185-
)?;
1192+
let loaded_image = self.open_protocol_exclusive::<LoadedImage>(image_handle)?;
1193+
1194+
let device_path = self.open_protocol_exclusive::<DevicePath>(loaded_image.device())?;
11861195

11871196
let device_handle = self.locate_device_path::<SimpleFileSystem>(&mut &*device_path)?;
11881197

1189-
self.open_protocol::<SimpleFileSystem>(
1190-
OpenProtocolParams {
1191-
handle: device_handle,
1192-
agent: image_handle,
1193-
controller: None,
1194-
},
1195-
OpenProtocolAttributes::Exclusive,
1196-
)
1198+
self.open_protocol_exclusive(device_handle)
11971199
}
11981200
}
11991201

uefi-test-runner/src/proto/media/known_disk.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,19 @@ fn test_create_file(directory: &mut Directory) {
145145
fn get_block_media_id(handle: Handle, bt: &BootServices) -> u32 {
146146
// This cannot be opened in `EXCLUSIVE` mode, as doing so
147147
// unregisters the `DiskIO` protocol from the handle.
148-
let block_io = bt
149-
.open_protocol::<BlockIO>(
150-
OpenProtocolParams {
151-
handle,
152-
agent: bt.image_handle(),
153-
controller: None,
154-
},
155-
OpenProtocolAttributes::GetProtocol,
156-
)
157-
.expect("Failed to get block I/O protocol");
158-
block_io.media().media_id()
148+
unsafe {
149+
let block_io = bt
150+
.open_protocol::<BlockIO>(
151+
OpenProtocolParams {
152+
handle,
153+
agent: bt.image_handle(),
154+
controller: None,
155+
},
156+
OpenProtocolAttributes::GetProtocol,
157+
)
158+
.expect("Failed to get block I/O protocol");
159+
block_io.media().media_id()
160+
}
159161
}
160162

161163
/// Tests raw disk I/O.

0 commit comments

Comments
 (0)