diff --git a/docs/WhatAndWhy/enhancedmemoryprotection.md b/docs/WhatAndWhy/enhancedmemoryprotection.md index 7da54a26b..ffbefdb8e 100644 --- a/docs/WhatAndWhy/enhancedmemoryprotection.md +++ b/docs/WhatAndWhy/enhancedmemoryprotection.md @@ -26,87 +26,126 @@ 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 occuring 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 @@ -114,7 +153,18 @@ protections, the PE/COFF IMAGE_DLLCHARACTERISTICS_NX_COMPAT DLL characteristic w 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 @@ -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 @@ -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