uefi: process: Fixes from PR · model-checking/verify-rust-std@8d5cf50
@@ -21,6 +21,12 @@ use crate::slice;
2121use crate::sync::atomic::{AtomicPtr, Ordering};
2222use crate::sys_common::wstr::WStrUnits;
232324+type BootInstallMultipleProtocolInterfaces =
25+unsafe extern "efiapi" fn(_: *mut r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
26+27+type BootUninstallMultipleProtocolInterfaces =
28+unsafe extern "efiapi" fn(_: r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
29+2430const BOOT_SERVICES_UNAVAILABLE: io::Error =
2531const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
2632@@ -231,6 +237,13 @@ impl DevicePath {
231237protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
232238) -> io::Result<DevicePath> {
233239let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
240+if path_vec[..path_vec.len() - 1].contains(&0) {
241+return Err(const_io_error!(
242+ io::ErrorKind::InvalidInput,
243+"strings passed to UEFI cannot contain NULs",
244+));
245+}
246+234247let path =
235248unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
236249@@ -267,17 +280,9 @@ impl DevicePath {
267280"DevicePathFromText Protocol not found"
268281))
269282}
270-}
271-272-impl AsRef<r_efi::protocols::device_path::Protocol> for DevicePath {
273-fn as_ref(&self) -> &r_efi::protocols::device_path::Protocol {
274-unsafe { self.0.as_ref() }
275-}
276-}
277283278-impl AsMut<r_efi::protocols::device_path::Protocol> for DevicePath {
279-fn as_mut(&mut self) -> &mut r_efi::protocols::device_path::Protocol {
280-unsafe { self.0.as_mut() }
284+pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
285+self.0.as_ptr()
281286}
282287}
283288@@ -292,74 +297,122 @@ impl Drop for DevicePath {
292297}
293298}
294299295-pub(crate) struct Protocol<T> {
300+pub(crate) struct OwnedProtocol<T> {
296301guid: r_efi::efi::Guid,
297302handle: NonNull<crate::ffi::c_void>,
298-protocol: Box<T>,
303+protocol: *mut T,
299304}
300305301-impl<T> Protocol<T> {
302-const fn new(
303-guid: r_efi::efi::Guid,
304-handle: NonNull<crate::ffi::c_void>,
305-protocol: Box<T>,
306-) -> Self {
307-Self { guid, handle, protocol }
308-}
309-310-pub(crate) fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result<Self> {
311-let boot_services: NonNull<r_efi::efi::BootServices> =
306+impl<T> OwnedProtocol<T> {
307+// FIXME: Consider using unsafe trait for matching protocol with guid
308+pub(crate) unsafe fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result<Self> {
309+let bt: NonNull<r_efi::efi::BootServices> =
312310boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
313-let mut protocol = Box::new(protocol);
311+let protocol: *mut T = Box::into_raw(Box::new(protocol));
314312let mut handle: r_efi::efi::Handle = crate::ptr::null_mut();
315313314+// FIXME: Move into r-efi once extended_varargs_abi_support is stablized
315+let func: BootInstallMultipleProtocolInterfaces =
316+unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) };
317+316318let r = unsafe {
317-((*boot_services.as_ptr()).install_protocol_interface)(
319+func(
318320&mut handle,
319-&mut guid,
320-r_efi::efi::NATIVE_INTERFACE,
321-protocol.as_mut() as *mut T as *mut crate::ffi::c_void,
321+&mut guid as *mut _ as *mut crate::ffi::c_void,
322+protocol as *mut crate::ffi::c_void,
323+crate::ptr::null_mut() as *mut crate::ffi::c_void,
322324)
323325};
324326325327if r.is_error() {
328+drop(unsafe { Box::from_raw(protocol) });
326329return Err(crate::io::Error::from_raw_os_error(r.as_usize()));
327330};
328331329332let handle = NonNull::new(handle)
330333.ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?;
331334332-Ok(Self::new(guid, handle, protocol))
335+Ok(Self { guid, handle, protocol })
333336}
334337335338pub(crate) fn handle(&self) -> NonNull<crate::ffi::c_void> {
336339self.handle
337340}
338341}
339342340-impl<T> Drop for Protocol<T> {
343+impl<T> Drop for OwnedProtocol<T> {
341344fn drop(&mut self) {
345+// Do not deallocate a runtime protocol
342346if let Some(bt) = boot_services() {
343347let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
344-unsafe {
345-((*bt.as_ptr()).uninstall_protocol_interface)(
348+// FIXME: Move into r-efi once extended_varargs_abi_support is stablized
349+let func: BootUninstallMultipleProtocolInterfaces = unsafe {
350+crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces)
351+};
352+let status = unsafe {
353+func(
346354self.handle.as_ptr(),
347-&mut self.guid,
348-self.protocol.as_mut() as *mut T as *mut crate::ffi::c_void,
355+&mut self.guid as *mut _ as *mut crate::ffi::c_void,
356+self.protocol as *mut crate::ffi::c_void,
357+crate::ptr::null_mut() as *mut crate::ffi::c_void,
349358)
350359};
360+361+// Leak the protocol in case uninstall fails
362+if status == r_efi::efi::Status::SUCCESS {
363+let _ = unsafe { Box::from_raw(self.protocol) };
364+}
351365}
352366}
353367}
354368355-impl<T> AsRef<T> for Protocol<T> {
369+impl<T> AsRef<T> for OwnedProtocol<T> {
356370fn as_ref(&self) -> &T {
357-&self.protocol
371+unsafe { self.protocol.as_ref().unwrap() }
372+}
373+}
374+375+pub(crate) struct OwnedTable<T> {
376+layout: crate::alloc::Layout,
377+ptr: *mut T,
378+}
379+380+impl<T> OwnedTable<T> {
381+pub(crate) fn from_table_header(hdr: &r_efi::efi::TableHeader) -> Self {
382+let header_size = hdr.header_size as usize;
383+let layout = crate::alloc::Layout::from_size_align(header_size, 8).unwrap();
384+let ptr = unsafe { crate::alloc::alloc(layout) as *mut T };
385+Self { layout, ptr }
386+}
387+388+pub(crate) const fn as_ptr(&self) -> *const T {
389+self.ptr
390+}
391+392+pub(crate) const fn as_mut_ptr(&self) -> *mut T {
393+self.ptr
358394}
359395}
360396361-impl<T> AsMut<T> for Protocol<T> {
362-fn as_mut(&mut self) -> &mut T {
363-&mut self.protocol
397+impl OwnedTable<r_efi::efi::SystemTable> {
398+pub(crate) fn from_table(tbl: *const r_efi::efi::SystemTable) -> Self {
399+let hdr = unsafe { (*tbl).hdr };
400+401+let owned_tbl = Self::from_table_header(&hdr);
402+unsafe {
403+crate::ptr::copy_nonoverlapping(
404+ tbl as *const u8,
405+ owned_tbl.as_mut_ptr() as *mut u8,
406+ hdr.header_size as usize,
407+)
408+};
409+410+ owned_tbl
411+}
412+}
413+414+impl<T> Drop for OwnedTable<T> {
415+fn drop(&mut self) {
416+unsafe { crate::alloc::dealloc(self.ptr as *mut u8, self.layout) };
364417}
365418}