diff --git a/CHANGELOG.md b/CHANGELOG.md index 1687eedf1..02c9d5693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ## uefi - [Unreleased] +### Added + +- 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] @@ -32,6 +43,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/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/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); + } +} 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)(