From 72b2e274f270810db803aeacee6be70e4778d9e7 Mon Sep 17 00:00:00 2001 From: Taylor Beebe Date: Tue, 9 Apr 2024 10:47:56 -0700 Subject: [PATCH 1/3] Paging Audit: Remove and Rename Some Tests Description Remove the AllocatedPagesAndPoolsAreProtected test because the state that it tests is not required by the Enhanced Memory Protection spec and a similar test is executed in the DxeMemoryProtectionTestApp. Rename the NullCheck test to NullPageIsRp to make it more clear what the test does. - [ ] Impacts functionality? - **Functionality** - Does the change ultimately impact how firmware functions? - Examples: Add a new library, publish a new PPI, update an algorithm, ... - [ ] Impacts security? - **Security** - Does the change have a direct security impact on an application, flow, or firmware? - Examples: Crypto algorithm change, buffer overflow fix, parameter validation improvement, ... - [ ] Breaking change? - **Breaking change** - Will anyone consuming this change experience a break in build or boot behavior? - Examples: Add a new library class, move a module to a different repo, call a function in a new library class in a pre-existing module, ... - [x] Includes tests? - **Tests** - Does the change include any explicit test code? - Examples: Unit tests, integration tests, robot tests, ... - [ ] Includes documentation? - **Documentation** - Does the change contain explicit documentation additions outside direct code modifications (and comments)? - Examples: Update readme file, add feature readme file, link to documentation on an a separate Web page, ... How This Was Tested Tested by building and running the test on Q35 Integration Instructions N/A --- .../UEFI/Dxe/App/DxePagingAuditTestApp.c | 96 +------------------ 1 file changed, 2 insertions(+), 94 deletions(-) diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c index 0b7c914482..3617bb58ab 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c +++ b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c @@ -977,97 +977,6 @@ IsMemoryAttributeProtocolPresent ( return UNIT_TEST_PASSED; } -/** - Allocates Pages and Pools of each memory type and - checks that the returned buffers have restrictive - access attributes. - - @param[in] Context Unit test context - - @retval UNIT_TEST_PASSED The unit test passed - @retval other The unit test failed -**/ -UNIT_TEST_STATUS -EFIAPI -AllocatedPagesAndPoolsAreProtected ( - IN UNIT_TEST_CONTEXT Context - ) -{ - UINTN Index; - BOOLEAN TestFailure; - UINTN *PageAllocations[EfiMaxMemoryType]; - UINTN *PoolAllocations[EfiMaxMemoryType]; - - DEBUG ((DEBUG_INFO, "%a Enter...\n", __FUNCTION__)); - - TestFailure = FALSE; - ZeroMem (PageAllocations, sizeof (PageAllocations)); - ZeroMem (PoolAllocations, sizeof (PoolAllocations)); - - for (Index = 0; Index < EfiMaxMemoryType; Index++) { - if ((Index != EfiConventionalMemory) && (Index != EfiPersistentMemory) && (Index != EfiUnacceptedMemoryType)) { - PageAllocations[Index] = AllocatePages (1); - if (PageAllocations[Index] == NULL) { - UT_LOG_ERROR ("Failed to allocate one page for memory type %d\n", Index); - TestFailure = TRUE; - } - - PoolAllocations[Index] = AllocatePool (8); - if (PoolAllocations[Index] == NULL) { - UT_LOG_ERROR ("Failed to allocate an 8 byte pool for memory type %d\n", Index); - TestFailure = TRUE; - } - } - } - - UT_ASSERT_NOT_EFI_ERROR (ValidatePageTableMapSize ()); - UT_ASSERT_NOT_EFI_ERROR (PopulatePageTableMap ()); - - for (Index = 0; Index < EfiMaxMemoryType; Index++) { - if ((Index != EfiConventionalMemory) && (Index != EfiPersistentMemory) && (Index != EfiUnacceptedMemoryType)) { - if (!ValidateRegionAttributes ( - &mMap, - (UINT64)PageAllocations[Index], - EFI_PAGE_SIZE, - EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP, - TRUE, - FALSE, - TRUE - )) - { - TestFailure = TRUE; - } - - if (!ValidateRegionAttributes ( - &mMap, - (UINT64)PoolAllocations[Index], - 8, - EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP, - TRUE, - FALSE, - TRUE - )) - { - TestFailure = TRUE; - } - } - } - - for (Index = 0; Index < EfiMaxMemoryType; Index++) { - if (PageAllocations[Index] != NULL) { - FreePages (PageAllocations[Index], 1); - } - - if (PoolAllocations[Index] != NULL) { - FreePool (PoolAllocations[Index]); - } - } - - UT_ASSERT_FALSE (TestFailure); - - return UNIT_TEST_PASSED; -} - /** Checks that the NULL page is not mapped or is EFI_MEMORY_RP. @@ -1080,7 +989,7 @@ AllocatedPagesAndPoolsAreProtected ( STATIC UNIT_TEST_STATUS EFIAPI -NullCheck ( +NullPageIsRp ( IN UNIT_TEST_CONTEXT Context ) { @@ -1627,8 +1536,7 @@ DxePagingAuditTestAppEntryPoint ( AddTestCase (Misc, "No pages are readable, writable, and executable", "Security.Misc.NoReadWriteExecute", NoReadWriteExecute, NULL, GeneralTestCleanup, NULL); AddTestCase (Misc, "Unallocated memory is EFI_MEMORY_RP", "Security.Misc.UnallocatedMemoryIsRP", UnallocatedMemoryIsRP, NULL, GeneralTestCleanup, NULL); AddTestCase (Misc, "Memory Attribute Protocol is present", "Security.Misc.IsMemoryAttributeProtocolPresent", IsMemoryAttributeProtocolPresent, NULL, NULL, NULL); - AddTestCase (Misc, "Calls to allocate pages and pools return buffers with restrictive access attributes", "Security.Misc.AllocatedPagesAndPoolsAreProtected", AllocatedPagesAndPoolsAreProtected, NULL, GeneralTestCleanup, NULL); - AddTestCase (Misc, "NULL page is EFI_MEMORY_RP", "Security.Misc.NullCheck", NullCheck, NULL, GeneralTestCleanup, NULL); + AddTestCase (Misc, "NULL page is EFI_MEMORY_RP", "Security.Misc.NullPageIsRp", NullPageIsRp, NULL, GeneralTestCleanup, NULL); AddTestCase (Misc, "MMIO Regions are EFI_MEMORY_XP", "Security.Misc.MmioIsXp", MmioIsXp, NULL, GeneralTestCleanup, NULL); AddTestCase (Misc, "Image code sections are EFI_MEMORY_RO and and data sections are EFI_MEMORY_XP", "Security.Misc.ImageCodeSectionsRoDataSectionsXp", ImageCodeSectionsRoDataSectionsXp, NULL, GeneralTestCleanup, NULL); AddTestCase (Misc, "BSP stack is EFI_MEMORY_XP and has EFI_MEMORY_RP guard page", "Security.Misc.BspStackIsXpAndHasGuardPage", BspStackIsXpAndHasGuardPage, NULL, GeneralTestCleanup, NULL); From fe57ba29efb856d51864389cd42e8b4aaf20a2c4 Mon Sep 17 00:00:00 2001 From: Taylor Beebe Date: Thu, 11 Apr 2024 08:44:44 -0700 Subject: [PATCH 2/3] Paging Audit: Use gEfiEventBeforeExitBootServicesGuid instead of gMuEventPreExitBootServicesGuid Description Now that the gEfiEventBeforeExitBootServicesGuid is available, we no longer need to use the Mu-specific gMuEventPreExitBootServicesGuid. - [x] Impacts functionality? - **Functionality** - Does the change ultimately impact how firmware functions? - Examples: Add a new library, publish a new PPI, update an algorithm, ... - [ ] Impacts security? - **Security** - Does the change have a direct security impact on an application, flow, or firmware? - Examples: Crypto algorithm change, buffer overflow fix, parameter validation improvement, ... - [ ] Breaking change? - **Breaking change** - Will anyone consuming this change experience a break in build or boot behavior? - Examples: Add a new library class, move a module to a different repo, call a function in a new library class in a pre-existing module, ... - [ ] Includes tests? - **Tests** - Does the change include any explicit test code? - Examples: Unit tests, integration tests, robot tests, ... - [ ] Includes documentation? - **Documentation** - Does the change contain explicit documentation additions outside direct code modifications (and comments)? - Examples: Update readme file, add feature readme file, link to documentation on an a separate Web page, ... How This Was Tested N/A Integration Instructions N/A --- .../PagingAudit/UEFI/Dxe/Driver/DxePagingAuditDriver.c | 2 +- .../AuditTests/PagingAudit/UEFI/DxePagingAuditDriver.inf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/Driver/DxePagingAuditDriver.c b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/Driver/DxePagingAuditDriver.c index 842552d343..582075c0f0 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/Driver/DxePagingAuditDriver.c +++ b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/Driver/DxePagingAuditDriver.c @@ -53,7 +53,7 @@ PagingAuditDriverEntryPoint ( TPL_CALLBACK, DumpPagingInfoEvent, NULL, - &gMuEventPreExitBootServicesGuid, + &gEfiEventBeforeExitBootServicesGuid, &Event ); DEBUG ((DEBUG_ERROR, "%a leave - %r\n", __FUNCTION__, Status)); diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditDriver.inf b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditDriver.inf index e5024f0230..31da8abd83 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditDriver.inf +++ b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditDriver.inf @@ -58,7 +58,7 @@ [Guids] gEfiDebugImageInfoTableGuid ## SOMETIMES_CONSUMES ## GUID gEfiMemoryAttributesTableGuid - gMuEventPreExitBootServicesGuid + gEfiEventBeforeExitBootServicesGuid gEfiHobMemoryAllocStackGuid ## SOMETIMES_CONSUMES ## SystemTable [Protocols] From 18f969a5f7072e6014aa650d9471324ace0715c5 Mon Sep 17 00:00:00 2001 From: Taylor Beebe Date: Tue, 9 Apr 2024 10:48:18 -0700 Subject: [PATCH 3/3] Paging Audit: Update the Readme to Reflect Updates Description - [ ] Impacts functionality? - **Functionality** - Does the change ultimately impact how firmware functions? - Examples: Add a new library, publish a new PPI, update an algorithm, ... - [ ] Impacts security? - **Security** - Does the change have a direct security impact on an application, flow, or firmware? - Examples: Crypto algorithm change, buffer overflow fix, parameter validation improvement, ... - [ ] Breaking change? - **Breaking change** - Will anyone consuming this change experience a break in build or boot behavior? - Examples: Add a new library class, move a module to a different repo, call a function in a new library class in a pre-existing module, ... - [ ] Includes tests? - **Tests** - Does the change include any explicit test code? - Examples: Unit tests, integration tests, robot tests, ... - [x] Includes documentation? - **Documentation** - Does the change contain explicit documentation additions outside direct code modifications (and comments)? - Examples: Update readme file, add feature readme file, link to documentation on an a separate Web page, ... How This Was Tested N/A Integration Instructions N/A --- .../AuditTests/PagingAudit/README.md | 151 +++++++++++++----- 1 file changed, 109 insertions(+), 42 deletions(-) diff --git a/UefiTestingPkg/AuditTests/PagingAudit/README.md b/UefiTestingPkg/AuditTests/PagingAudit/README.md index 011d531a88..98c9e0f467 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/README.md +++ b/UefiTestingPkg/AuditTests/PagingAudit/README.md @@ -1,5 +1,85 @@ # Paging Audit +## Contents + +- [Paging Audit](#paging-audit) + - [Contents](#contents) + - [DXE Paging Audit](#dxe-paging-audit) + - [DXE Driver](#dxe-driver) + - [DXE Shell App](#dxe-shell-app) + - [Mode 1: Shell-Based Unit Test](#mode-1-shell-based-unit-test) + - [Mode 2: Paging Audit Collection Tool](#mode-2-paging-audit-collection-tool) + - [SMM Paging Audit](#smm-paging-audit) + - [SMM Driver](#smm-driver) + - [SMM Shell App](#smm-shell-app) + - [Parsing the Paging Data](#parsing-the-paging-data) + - [Platform Configuration](#platform-configuration) + - [SMM Paging Audit Configuration](#smm-paging-audit-configuration) + - [DXE Paging Audit Driver Configuration](#dxe-paging-audit-driver-configuration) + - [DXE Paging Audit App Configuration](#dxe-paging-audit-app-configuration) + - [Copyright](#copyright) + +## DXE Paging Audit + +The DXE paging audit is a tool to analyze the page/translation tables of the platform to check +compliance with +[Enhanced Memory Protection](https://microsoft.github.io/mu/WhatAndWhy/enhancedmemoryprotection/), +debug paging related issues, and understand the memory layout of the platform. The DXE version +of the audit operates only on the page/translation tables of the DXE environment and not the +tables used in SMM. + +### DXE Driver + +The DXE Driver registers an event to be notified on Mu Pre Exit Boot Services (to change this, +replace gEfiEventBeforeExitBootServicesGuid with a different event GUID), which will then trigger +the paging information collection. The driver will then save the collected information to +an available simple file system. The driver version of the DXE paging audit should be used +when the intent is to capture a snapshot of the page/translation table data at an arbitrary +point in boot. + +### DXE Shell App + +The DXE version of UEFI shell app has two modes of operation and **does not require** +**the DXE driver**. + +#### Mode 1: Shell-Based Unit Test + +Calling the app in the following way: + +`DxePagingAuditTestApp.efi` +OR +`DxePagingAuditTestApp.efi -r` + +Will run the app as a shell-based unit test. The following tests will be run and the +results will be saved to an XML file in the same file system as the app (or the next +available writable simple file system): + +- **NoReadWriteExecute:** Checks if the page/translation table has any readable, writable, +and executable regions. +- **UnallocatedMemoryIsRP:** Checks that all EfiConventionalMemory is EFI_MEMORY_RP or +is not mapped. +- **IsMemoryAttributeProtocolPresent:** Checks if the EFI Memory Attribute Protocol +is installed. +- **NullPageIsRp:** Checks if page 0 is EFI_MEMORY_RP or is not mapped. +- **MmioIsXp:** Checks that MMIO regions in the EFI memory map are EFI_MEMORY_XP. +- **ImageCodeSectionsRoDataSectionsXp:** Checks that loaded image sections containing +code are EFI_MEMORY_RO and sections containing data are EFI_MEMORY_XP. +- **BspStackIsXpAndHasGuardPage:** Checks that the stack is EFI_MEMORY_XP and has an +EFI_MEMORY_RP page at the base to catch overflow. +- **MemoryOutsideEfiMemoryMapIsInaccessible:** Checks that memory ranges not in +the EFI memory map EFI_MEMORY_RP or is not mapped. + +#### Mode 2: Paging Audit Collection Tool + +Calling the app in the following way: + +`DxePagingAuditTestApp.efi -d` + +Will collect paging information and save the data in the same file system as +the app (or the next available writable simple file system). See the +[Parsing the Paging Data](#parsing-the-paging-data) for instructions on parsing +the collected data. + ## SMM Paging Audit SMM is a privileged mode of the IA32/X64 cpu architecture. In this environment nearly all system state can @@ -23,46 +103,44 @@ The UEFI shell application collects system information from the DXE environment communicates to the SMM driver/handler to collect necessary info from SMM. It then writes this data to files for parsing by Python scripts. -## DXE Paging Audit +## Parsing the Paging Data -The DXE version of the paging audit and driver have overlapping purpose. Both are capable of -inspecting the page/translation tables to collect all leaf entries for parsing using -Windows\PagingReportGenerator.py and both are compatible with X64 and AARCH64 architectures. +The Python Windows\PagingReportGenerator.py script will parse the *.dat files into +a human-readable HTML report file to inspect +the page table at the collection point. The Results tab of the HTML shows the results of testing +the parsed data against the tests run in the shell app, and each failed test presents a filter +button to show the regions of memory which do not pass the test. -### DXE Driver +Run the following command for help with the script: -The DXE Driver registers an event to be notified on Mu Pre Exit Boot Services (to change this, -replace gMuEventPreExitBootServicesGuid with a different event GUID), which will then trigger -the paging information collection. The driver will then save the collected information to -an available simple file system. The driver version of the DXE paging audit should be used -when the intent is to capture a snapshot of the page/translation table at a point in boot at -which the shell app cannot be run. +`PagingReportGenerator.py -h` -### DXE Version App +The script is run with the following command: -The DXE version of UEFI shell app has two modes of operation and **does not require the DXE driver**. -Calling the app without any parameters will run it as a unit test with the only current test being -to check every leaf entry in the page/translation table to ensure that no page is Read/Write/Execute. -Calling the app with the '-d' parameter will collect paging information and attempt to save it to the -same file system containing the app. If it cannot save to the app's file system, it will save to the -first available simple file system. +```cmd +PagingReportGenerator.py -i -o [-p ] [--PlatformVersion ] [-l ] [--debug] +``` -## Python Script +**Required Input Parameters:** + `-i `: The directory containing the *.dat files to be parsed. + `-o `: The name of the HTML report file to be generated. -The Python script will parse the *.dat files into a human-readable HTML report file to inspect -the page table at the collection point. The Results tab of the HTML checks the data against our suggested -rules to act as a barometer for the security of the target system. +**Optional Input Parameters:** + `-p `: The name of the platform the data was collected on. + `--PlatformVersion `: The version of the platform the data was collected on. + `-l `: The name of the log file to be generated. + `--debug`: Set logging level to DEBUG (will be INFO by default). -## Usage +## Platform Configuration -### SMM Paging Audit Usage +### SMM Paging Audit Configuration ```text -[PcdsFixedAtBuild.X64] +[PcdsFixedAtBuild] # Optional: Virtual platforms that do not support SMRRs can add below change to skip the auditing related to SMRR gUefiTestingPkgTokenSpaceGuid.PcdPlatformSmrrUnsupported|TRUE -[Components.X64] +[Components] UefiTestingPkg/AuditTests/PagingAudit/UEFI/SmmPagingAuditDriver.inf UefiTestingPkg/AuditTests/PagingAudit/UEFI/SmmPagingAuditTestApp.inf ``` @@ -78,18 +156,16 @@ to a USB key. Boot the target system running the new firmware to the shell and r a set of *.dat files on an available simple file system on the target system. Run the Python script on the data to create the HTML report. -### DXE Paging Audit Usage - -#### DXE Paging Audit Driver +### DXE Paging Audit Driver Configuration Add the following to the platform DSC file: ```text -[PcdsFixedAtBuild.X64] +[PcdsFixedAtBuild] # Optional: Virtual platforms that do not support SMRRs can add below change to skip the auditing related to SMRR gUefiTestingPkgTokenSpaceGuid.PcdPlatformSmrrUnsupported|TRUE -[Components.X64] +[Components] UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditDriver.inf ``` @@ -111,12 +187,12 @@ Example if the paging audit files are on FS1 and the USB/virtual drive FS0: copy FS1:\*.dat FS0:\ ``` -#### DXE Paging Audit App +### DXE Paging Audit App Configuration Add the following entry to platform dsc file and compile the new firmware image: ```text -[Components.X64] +[Components] UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditTestApp.inf ``` @@ -132,15 +208,6 @@ FS0:\DxePagingAuditTestApp.efi the USB/virtual drive FS0 -### Parsing the .dat files - -Run the Python Windows\PagingReportGenerator.py script against the collected .dat files. Use the following -command for detailed script instruction: - -```cmd -PagingReportGenerator.py -h -``` - ## Copyright Copyright (c) Microsoft Corporation.