Skip to content

Commit

Permalink
Do larger rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
os-d committed Oct 2, 2024
1 parent 2715149 commit bb0f78b
Showing 1 changed file with 133 additions and 64 deletions.
197 changes: 133 additions & 64 deletions docs/WhatAndWhy/enhancedmemoryprotection.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,95 +26,145 @@ to be updated to adhere to these new requirements and our collective commitment
to progress will pave the way to a more secure and resilient digital future.
**Project Mu serves as a reference implementation for Enhanced Memory Protections.**

## Terminology

This document describes two states of memory protections: hardware state and
software state. The hardware state is the state of the page table and the software
state is the state of the Global Coherency Domain (GCD). These states need to
be in sync with each other, but different architectures may implement the
mapping from GCD state to page table state differently. This document uses the
GCD terminology as it is universal. This section serves to define the expectations
that this document makes when using the GCD terminology.

| Attribute | Description |
|-------------------------------|--------------------------------------------------------------------------|
| `EFI_MEMORY_XP` | Memory is non-executable. |
| `EFI_MEMORY_RO` | Memory is read-only. |
| `EFI_MEMORY_RP` | Memory is read-protected or unmapped. A CPU fault occurs if accessed. |

## Condensed Requirements List

1: The UEFI 2.10 Memory Attribute Protocol must be produced.
2: No address range can be simultaneously readable, writable, and executable.
3: Unallocated memory must be marked EFI_MEMORY_RP or be unmapped.
4: Address space which is not present in the Global Coherency Domain must cause a
CPU fault if accessed. This is a future requirement.
5: Calls to EFI_BOOT_SERVICES.AllocatePages and EFI_BOOT_SERVICES.AllocatePool
1: All memory available to the platform must be described in the GCD.
2: No address range can be simultaneously readable, writable, and executable. This means every GCD entry must have at
least one of EFI_MEMORY_XP, EFI_MEMORY_RO, or EFI_MEMORY_RP set.
3: Loaded image sections marked with the data characteristic must be EFI_MEMORY_XP.
4: Loaded image sections marked with the code characteristic must be EFI_MEMORY_RO.
5: PE Loaders must check the NX_COMPAT flag of loaded images to determine
compatibility with the above memory protection requirements.
6: MMIO ranges must be marked EFI_MEMORY_XP.
7: Unallocated memory must be marked EFI_MEMORY_RP.
8: Address space which is not present in the Global Coherency Domain must cause a
CPU fault if accessed.
9: Calls to EFI_BOOT_SERVICES.AllocatePages and EFI_BOOT_SERVICES.AllocatePool
must return memory with the EFI_MEMORY_XP attribute.
6: Page 0 in physical system memory must be marked EFI_MEMORY_RP or be unmapped.
7: AP and BSP stacks must be marked EFI_MEMORY_XP.
8: AP and BSP stacks must have an EFI_MEMORY_RP page at the bottom to catch overflow.
9: MMIO ranges must be marked EFI_MEMORY_XP.
10: Loaded image sections marked with the data characteristic must be EFI_MEMORY_XP.
11: Loaded image sections the code characteristic must be EFI_MEMORY_RO.
12: PE Loaders must check the NX_COMPAT flag of loaded images to determine
compatibility with the above memory protection requirements.
10: AP and BSP stacks must be marked EFI_MEMORY_XP.
11: AP and BSP stacks must have an EFI_MEMORY_RP page at the bottom to catch overflow.
12: Page 0 in physical system memory must be marked EFI_MEMORY_RP.
13: The UEFI 2.10 Memory Attribute Protocol must be produced.

## Runtime Configurable Protections
## Expanded Requirements List

To enable memory protection in consumer shipped devices, runtime
configurability options need to be present to respond to edge cases
and accommodate non-compliant option ROMs. It is up to the platform
developer to determine what levers will be available and how faults are handled.
![Example Compliant Memory Range](../img/memory_range.png)

## Memory Attribute Protocol
### All Memory is Described in the GCD

A necessity for increasing the security posture is the availability of
the Memory Attribute Protocol. Added in UEFI Spec 2.10, the protocol
enables setting and getting EFI memory attributes in the UEFI environment.
Project Mu hosts an example implementation of this protocol.
All memory that a platform can access, whether through MMIO, protocols like CXL, or directly attached, must be
described in the GCD with an appropriate memory type. The GCD is UEFI's software state of memory. If memory is not
described here, we cannot safely manage the security of that memory.

## Exception Handling
### No R/W/X Regions

Increasing the security posture of UEFI implementations will increase the
frequency of access violations. Exceptions should either cause a reset or
transition the memory protection state into compatibility mode. Platform
developers should also take care to ensure their exception handling logic
provides enough data to distinguish between fault types and root cause
failures. These access violations are often helpful for identifying programmer
errors and rooting out critical bugs before they become CVEs.
This has been a system software requirement for decades at this point and should be self-explanatory. Self-modifying
executable regions are an easy attack vector for a bad actor. As such, all memory in the GCD must have one or more of
EFI_MEMORY_XP, EFI_MEMORY_RO, and EFI_MEMORY_RP set.

## Memory Management
### Image Data Sections Must Be EFI_MEMORY_XP

### General Memory Management
Image data sections must be read from at a minimum and often need to be written to. They must not contain any
executable code. Executable code must be in an image section marked with the code characteristic. It is appropriate
to mark some image data sections EFI_MEMORY_RO in addition to EFI_MEMORY_XP, if they are read-only sections. All image
data sections must be marked EFI_MEMORY_XP to prevent execution from occurring from these regions. This is a requirement
to fulfill the No R/W/X Regions requirement and prevents common attack vectors for bad actors writing attack code to
a memory region and forcing the processor to execute it.

![Example Compliant Memory Range](../img/memory_range.png)
### Image Code Sections Must Be EFI_MEMORY_RO

At no point during boot should any addressable memory be readable, writable,
and executable. To reach this heightened security bar, all unallocated memory
should be marked EFI_MEMORY_RP or be unmapped. Addressable memory ranges which
are not present in the Global Coherency Domain should also be read-protected or
unmapped. When a module makes a call to allocate a buffer (even if that buffer
is of type EfiBootServicesCode, EfiRuntimeServicesCode, or EfiLoaderCode),
the returned page/pool must be non-executable. The module which called for the
allocation will be expected to utilize the Memory Attribute Protocol to
manipulate the attributes of the buffer to be either writable or executable
but not both.
Image code sections must be read and executed, but must not be writeable. This is a requirement to fulfill the No
R/W/X Regions requirement and prevents the same problem of bad actors editing a running drivers memory to cause it
to execute malicious code.

#### Special Memory Ranges
### MMIO Ranges Must Be EFI_MEMORY_XP

* UEFI must apply EFI_MEMORY_RP to the NULL page or don't map it to help guard against NULL dereferences.
* AP and BSP stacks must be marked EFI_MEMORY_XP to prevent execution from the stack with
a page marked EFI_MEMORY_RP at the base of the stack to prevent stack overflow.
* MMIO ranges should be marked EFI_MEMORY_XP.
All devices connected to a system should be considered untrusted and must not be allowed to execute code. This is also
a common attack vector for a bad actor to connect a compromised device and force the host system to execute malicious
code from it.

## PE Loader
### Unallocated Memory Must Be EFI_MEMORY_RP

![Example of Loaded Image Ranges](../img/loaded_images.png)
This is a safety as well as security requirement. By marking unallocated memory EFI_MEMORY_RP, any access outside of
legitimately allocated memory will cause a CPU fault, catching a large set of buffer under/overflows and use-after-free
cases, which are both functional concerns as well as attack vectors.

On loading and prior to execution of an EFI image, the PE loader must apply
EFI_MEMORY_XP to sections marked with the data characteristic and EFI_MEMORY_RO
to sections marked with the code characteristic. Applying these page protections
requires loaded images to meet the following criteria:
This adds a new potential crash to code that may have "just worked" before, but it allows a platform to discover the
safety and security issues pre-production and enforces defined behavior where before there was undefined behavior.

1. Section flags must not combine IMAGE_SCN_MEM_WRITE and IMAGE_SCN_MEM_EXECUTE for any
given section.
2. The PE image sections are aligned to page granularity.
3. The PE image must not contain any self-modifying code.
### Memory Not in the GCD Must Cause a CPU Fault on Access

This is a converse of the requirement that all memory that a platform can access is described in the GCD: everything
else must, therefore, cause a fault when accessed, because it is not memory a platform can access.

### AllocatePages and AllocatePool Must Return Memory with EFI_MEMORY_XP

DXE Core cannot rely on drivers to set the correct attributes. Most memory allocations occur without the consumer
setting any attributes on the memory region. Furthermore, it is unsafe for pool allocations not in a multiple of the
EFI_PAGE_SIZE to attempt to set attributes, there are other consumers using this pool space. If the core does not set
the attributes, the attributes will not be set.

EFI_MEMORY_XP is the attribute that must be set because it is the general case: most memory will be marked
EFI_MEMORY_XP. Even memory that will be used for an image code section must be marked EFI_MEMORY_XP originally,
because the PE loader must write the code section to that memory before it marks it EFI_MEMORY_RO and removes
EFI_MEMORY_XP.

### AP/BSP Stacks Must Be EFI_MEMORY_XP

This continues the requirement that non-code sections must be marked EFI_MEMORY_XP. This closes a common attacker
scenario to put code on the stack and then force the processor to execute from it.

### AP/BSP Stacks Must Have EFI_MEMORY_RP Page at the Bottom

Commonly known as Stack Guard, this feature places a guard page marked EFI_MEMORY_RP at the bottom of the stack. This
catches stack overflows by causing a CPU fault if this guard page is read from or written to. Stack overflows are both
common attack vectors and common programming errors that require being caught during development.

## NX_COMPAT Characteristic
This also adds a new potential crash during execution in code that may have "just worked" before, but similarly allows
these problems to be solved pre-production and enforces defined behavior instead of undefined.

### EFI Memory Attributes Protocol Must Be Installed

The Memory Attributes Protocol, added in UEFI spec 2.10, provides a method for bootloaders to interact with UEFI's page
tables before they create their own page tables. This allows them to enforce memory protections on their own images and
allocations, closing further attack vectors.

### PE Loaders Must Check the NX_COMPAT Flag for Compatibility

Many bootloaders and OPROMs will not have implemented support for enhanced protections on
image memory, allocated buffers, and other memory ranges. To indicate support for enhanced
protections, the PE/COFF IMAGE_DLLCHARACTERISTICS_NX_COMPAT DLL characteristic will be used.
Modules with this characteristic are expected to be compliant with enhanced memory protection
and should utilize the Memory Attribute Protocol to manipulate the attributes of memory they
allocate. If a module is loaded without this characteristic, the platform should enter
compatibility mode.
[compatibility mode](#compatibility-mode) if the platform chooses to support compatibility
mode.

![Example of Loaded Image Ranges](../img/loaded_images.png)

Applying these page protections requires loaded images to meet the following criteria, signified by setting the
NX_COMPAT characteristic:

1. Section flags must not combine IMAGE_SCN_MEM_WRITE and IMAGE_SCN_MEM_EXECUTE for any
given section.
2. The PE image sections are aligned to page granularity.
3. The PE image must not contain any self-modifying code.

## Compatibility Mode

Expand All @@ -127,9 +177,9 @@ deviations from the enhanced memory protection definition:
2. All images loaded from the start of compatibility mode will no longer have
restrictive access attributes applied to the memory ranges in which they are loaded.
3. The Memory Attribute Protocol will be uninstalled.
4. Page zero will be mapped.
4. Page zero will be mapped if it resides in system memory.
5. Legacy BIOS memory (the lower 640K range) will be mapped as readable, writable, and
executable.
executable on AMD64 systems.

### A Note on User Notification of Compatibility Mode

Expand All @@ -141,6 +191,25 @@ platform. In the future, platform developers should consider adding a TPM (Trust
Platform Module) measurement when the system enters compatibility mode to have platform
enforcement of memory protections.

## Additional Considerations

## Runtime Configurable Protections

To enable memory protection in consumer shipped devices, runtime
configurability options need to be present to respond to edge cases
and accommodate non-compliant option ROMs. It is up to the platform
developer to determine what levers will be available and how faults are handled.

## Exception Handling

Increasing the security posture of UEFI implementations will increase the
frequency of access violations. Exceptions should either cause a reset or
transition the memory protection state into compatibility mode. Platform
developers should also take care to ensure their exception handling logic
provides enough data to distinguish between fault types and root cause
failures. These access violations are often helpful for identifying programmer
errors and rooting out critical bugs before they become CVEs.

## Closing

It will take substantial work to update legacy code to adhere to these new security
Expand Down

0 comments on commit bb0f78b

Please sign in to comment.