From ff7d8d8eb0224b5d6b72f54d46383849868109ef Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 24 May 2022 17:39:28 -0400 Subject: [PATCH 1/2] Add Revision constants and constify Revision methods Add constants for all the EFI versions (from section 4.3 "EFI System Table"). Also make the new/major/minor methods of Revision const. --- CHANGELOG.md | 5 +++++ src/table/revision.rs | 43 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1687eedf1..89ce95818 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## uefi - [Unreleased] +### Added + +- Added EFI revision constants to `Revision`. + ## uefi-macros - [Unreleased] ## uefi-services - [Unreleased] @@ -32,6 +36,7 @@ - `DevicePath` is now a DST that represents an entire device path. The `DevicePathInstance` and `DevicePathNode` provide views of path instances and nodes, respectively. +- The methods of `Revision` are now `const`. ### Fixed diff --git a/src/table/revision.rs b/src/table/revision.rs index ef2577f9e..c79810936 100644 --- a/src/table/revision.rs +++ b/src/table/revision.rs @@ -9,21 +9,41 @@ use core::fmt; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub struct Revision(u32); +// Allow missing docs, there's nothing useful to document about these +// constants. +#[allow(missing_docs)] +impl Revision { + pub const EFI_1_02: Self = Self::new(1, 2); + pub const EFI_1_10: Self = Self::new(1, 10); + pub const EFI_2_00: Self = Self::new(2, 00); + pub const EFI_2_10: Self = Self::new(2, 10); + pub const EFI_2_20: Self = Self::new(2, 20); + pub const EFI_2_30: Self = Self::new(2, 30); + pub const EFI_2_31: Self = Self::new(2, 31); + pub const EFI_2_40: Self = Self::new(2, 40); + pub const EFI_2_50: Self = Self::new(2, 50); + pub const EFI_2_60: Self = Self::new(2, 60); + pub const EFI_2_70: Self = Self::new(2, 70); + pub const EFI_2_80: Self = Self::new(2, 80); + pub const EFI_2_90: Self = Self::new(2, 90); +} + impl Revision { /// Creates a new revision. - pub fn new(major: u16, minor: u16) -> Self { - let (major, minor) = (u32::from(major), u32::from(minor)); + pub const fn new(major: u16, minor: u16) -> Self { + let major = major as u32; + let minor = minor as u32; let value = (major << 16) | minor; Revision(value) } /// Returns the major revision. - pub fn major(self) -> u16 { + pub const fn major(self) -> u16 { (self.0 >> 16) as u16 } /// Returns the minor revision. - pub fn minor(self) -> u16 { + pub const fn minor(self) -> u16 { self.0 as u16 } } @@ -35,3 +55,18 @@ impl fmt::Debug for Revision { write!(f, "{}.{}.{}", major, minor / 10, minor % 10) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_revision() { + let rev = Revision::EFI_2_31; + assert_eq!(rev.major(), 2); + assert_eq!(rev.minor(), 31); + assert_eq!(rev.0, 0x0002_001f); + + assert!(Revision::EFI_1_10 < Revision::EFI_2_00); + } +} From ae47b3421f587d996cdf0845cd78ab7d17d1aa1f Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 24 May 2022 17:54:29 -0400 Subject: [PATCH 2/2] Check table version before calling UEFI 2.0+ functions The create_event_ex function (in boot services) and query_variable_info (in runtime services) were added to their respective tables in UEFI 2.0. In earlier versions these functions can't be called, so check the table revision before using these function pointers. --- CHANGELOG.md | 7 +++++++ src/table/boot.rs | 9 ++++++++- src/table/runtime.rs | 9 ++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89ce95818..02c9d5693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ - Added EFI revision constants to `Revision`. +### Fixed + +- The `BootServices::create_event_ex` and + `RuntimeServices::query_variable_info` methods now check the table + version to make sure it's 2.0 or higher before calling the associated + function pointers. This prevents potential invalid pointer access. + ## uefi-macros - [Unreleased] ## uefi-services - [Unreleased] diff --git a/src/table/boot.rs b/src/table/boot.rs index f0ecd5f2c..2307d9551 100644 --- a/src/table/boot.rs +++ b/src/table/boot.rs @@ -1,6 +1,6 @@ //! UEFI services available during boot. -use super::Header; +use super::{Header, Revision}; use crate::data_types::Align; use crate::proto::device_path::{DevicePath, FfiDevicePath}; #[cfg(feature = "exts")] @@ -437,6 +437,9 @@ impl BootServices { /// More than one event of type `EventType::TIMER` may be part of a single event group. However, /// there is no mechanism for determining which of the timers was signaled. /// + /// This operation is only supported starting with UEFI 2.0; earlier + /// versions will fail with [`Status::UNSUPPORTED`]. + /// /// # Safety /// /// The caller must ensure they are passing a valid `Guid` as `event_group`, if applicable. @@ -448,6 +451,10 @@ impl BootServices { notify_ctx: Option>, event_group: Option>, ) -> Result { + if self.header.revision < Revision::EFI_2_00 { + return Err(Status::UNSUPPORTED.into()); + } + let mut event = MaybeUninit::::uninit(); (self.create_event_ex)( diff --git a/src/table/runtime.rs b/src/table/runtime.rs index ef20eed15..6aa9087bf 100644 --- a/src/table/runtime.rs +++ b/src/table/runtime.rs @@ -1,6 +1,6 @@ //! UEFI services available at runtime, even after the OS boots. -use super::Header; +use super::{Header, Revision}; #[cfg(feature = "exts")] use crate::data_types::FromSliceWithNulError; use crate::result::Error; @@ -248,11 +248,18 @@ impl RuntimeServices { /// Get information about UEFI variable storage space for the type /// of variable specified in `attributes`. /// + /// This operation is only supported starting with UEFI 2.0; earlier + /// versions will fail with [`Status::UNSUPPORTED`]. + /// /// See [`VariableStorageInfo`] for details of the information returned. pub fn query_variable_info( &self, attributes: VariableAttributes, ) -> Result { + if self.header.revision < Revision::EFI_2_00 { + return Err(Status::UNSUPPORTED.into()); + } + let mut info = VariableStorageInfo::default(); unsafe { (self.query_variable_info)(