Skip to content

Commit 35051a3

Browse files
nicholasbishopGabrielMajeri
authored andcommitted
Add MemoryProtection protocol
This corresponds to the `EFI_MEMORY_ATTRIBUTE_PROTOCOL` proposal: https://bugzilla.tianocore.org/show_bug.cgi?id=3519 The protocol is part of a push to add better memory protection to UEFI: https://github.com/MicrosoftDocs/windows-driver-docs/blob/abb7dfa01467a300eefe589a4a8f9353199c0ade/windows-driver-docs-pr/bringup/uefi-ca-memory-mitigation-requirements.md This is not yet part of a released UEFI Specification, but support for using the protocol has already been added to shim and Fedora's fork of grub * rhboot/shim@825d993 * rhboot/grub2@aa3c4f6 By our usual naming conventions, `EFI_MEMORY_ATTRIBUTE_PROTOCOL` would translate to a struct named `MemoryAttribute`. I went with `MemoryProtection` instead because: 1. We don't typically include `Protocol` in the name of our `Protocol` structs, but there's already a `MemoryAttribute` type in the crate, which is the bitflag enum that describes the actual attributes. Since the two types are used together, the naming conflict would be confusing. 2. This protocol only gets and sets the RO/RP/XP memory attribute flags, so the generic `EFI_MEMORY_ATTRIBUTE_PROTOCOL` name is a bit misleading; there are many other memory attributes that it does not cover. I put the new protocol under `proto::security` since the proposal would place the new protocol in the UEFI Specification under section 37 "Secure Technologies"; `proto::secure_technologies` is a bit verbose so went with `proto::security` instead.
1 parent c1a8f3f commit 35051a3

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
This eliminates the need to explicitly access the `interface` field,
1010
which is now marked as deprecated.
1111
- Implemented `core::fmt::Write` for the `Serial` protocol.
12+
- Added the `MemoryProtection` protocol.
1213

1314
### Fixed
1415

src/proto/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,5 @@ pub mod media;
7272
pub mod network;
7373
pub mod pi;
7474
pub mod rng;
75+
pub mod security;
7576
pub mod shim;
+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use crate::proto::Protocol;
2+
use crate::table::boot::MemoryAttribute;
3+
use crate::{unsafe_guid, Result, Status};
4+
use core::ops::Range;
5+
6+
/// Protocol for getting and setting memory protection attributes.
7+
///
8+
/// This corresponds to the `EFI_MEMORY_ATTRIBUTE_PROTOCOL` [proposal].
9+
///
10+
/// [proposal]: https://bugzilla.tianocore.org/show_bug.cgi?id=3519
11+
#[repr(C)]
12+
#[unsafe_guid("f4560cf6-40ec-4b4a-a192-bf1d57d0b189")]
13+
#[derive(Protocol)]
14+
pub struct MemoryProtection {
15+
get_memory_attributes: unsafe extern "efiapi" fn(
16+
this: *const Self,
17+
base_address: u64,
18+
length: u64,
19+
attributes: *mut MemoryAttribute,
20+
) -> Status,
21+
22+
set_memory_attributes: unsafe extern "efiapi" fn(
23+
this: *const Self,
24+
base_address: u64,
25+
length: u64,
26+
attributes: MemoryAttribute,
27+
) -> Status,
28+
29+
clear_memory_attributes: unsafe extern "efiapi" fn(
30+
this: *const Self,
31+
base_address: u64,
32+
length: u64,
33+
attributes: MemoryAttribute,
34+
) -> Status,
35+
}
36+
37+
impl MemoryProtection {
38+
/// Get the attributes of a memory region.
39+
///
40+
/// The attribute mask this returns will only contain bits in the
41+
/// set of [`READ_PROTECT`], [`EXECUTE_PROTECT`], and [`READ_ONLY`].
42+
///
43+
/// If the attributes are not consistent within the region,
44+
/// [`Status::NO_MAPPING`] is returned.
45+
///
46+
/// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT
47+
/// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT
48+
/// [`READ_ONLY`]: MemoryAttribute::READ_ONLY
49+
pub fn get_memory_attributes(&self, byte_region: Range<u64>) -> Result<MemoryAttribute> {
50+
let mut attributes = MemoryAttribute::empty();
51+
let (base_address, length) = range_to_base_and_len(byte_region);
52+
unsafe {
53+
(self.get_memory_attributes)(self, base_address, length, &mut attributes)
54+
.into_with_val(|| attributes)
55+
}
56+
}
57+
58+
/// Set the attributes of a memory region.
59+
///
60+
/// The valid attributes to set are [`READ_PROTECT`],
61+
/// [`EXECUTE_PROTECT`], and [`READ_ONLY`].
62+
///
63+
/// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT
64+
/// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT
65+
/// [`READ_ONLY`]: MemoryAttribute::READ_ONLY
66+
pub fn set_memory_attributes(
67+
&self,
68+
byte_region: Range<u64>,
69+
attributes: MemoryAttribute,
70+
) -> Result {
71+
let (base_address, length) = range_to_base_and_len(byte_region);
72+
unsafe { (self.set_memory_attributes)(self, base_address, length, attributes).into() }
73+
}
74+
75+
/// Clear the attributes of a memory region.
76+
///
77+
/// The valid attributes to clear are [`READ_PROTECT`],
78+
/// [`EXECUTE_PROTECT`], and [`READ_ONLY`].
79+
///
80+
/// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT
81+
/// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT
82+
/// [`READ_ONLY`]: MemoryAttribute::READ_ONLY
83+
pub fn clear_memory_attributes(
84+
&self,
85+
byte_region: Range<u64>,
86+
attributes: MemoryAttribute,
87+
) -> Result {
88+
let (base_address, length) = range_to_base_and_len(byte_region);
89+
unsafe { (self.clear_memory_attributes)(self, base_address, length, attributes).into() }
90+
}
91+
}
92+
93+
/// Convert a byte `Range` to `(base_address, length)`.
94+
fn range_to_base_and_len(r: Range<u64>) -> (u64, u64) {
95+
(r.start, r.end.checked_sub(r.start).unwrap())
96+
}
97+
98+
#[cfg(test)]
99+
mod tests {
100+
use super::*;
101+
102+
#[test]
103+
fn test_range_conversion() {
104+
assert_eq!(range_to_base_and_len(2..5), (2, 3));
105+
}
106+
}

src/proto/security/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! Protocols related to secure technologies.
2+
3+
mod memory_protection;
4+
pub use memory_protection::MemoryProtection;

0 commit comments

Comments
 (0)