diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/AArch64/DxePagingAuditTests.c b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/AArch64/DxePagingAuditTests.c deleted file mode 100644 index 8455c0e23e..0000000000 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/AArch64/DxePagingAuditTests.c +++ /dev/null @@ -1,145 +0,0 @@ -/** @file -- DxePagingAuditTests.c - ARM64 implementations for DXE paging audit tests - - Copyright (c) Microsoft Corporation. - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include -#include -#include "../DxePagingAuditTestApp.h" - -#define TT_ADDRESS_MASK (0xFFFFFFFFFULL << 12) -#define IS_TABLE(page, level) ((level == 3) ? FALSE : (((page) & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY)) -#define IS_BLOCK(page, level) ((level == 3) ? (((page) & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3) : ((page & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY)) -#define ROOT_TABLE_LEN(T0SZ) (TT_ENTRY_COUNT >> ((T0SZ) - 16) % 9) -#define IS_VALID 0x1 -#define IS_READ_WRITE(page) (((page & TT_AP_RW_RW) != 0) || ((page & TT_AP_MASK) == 0)) -#define IS_EXECUTABLE(page) ((ArmReadCurrentEL () == AARCH64_EL2) ? ((page & TT_XN_MASK) == 0) : ((page & TT_UXN_MASK) == 0 || (page & TT_PXN_MASK) == 0)) -#define IS_ACCESSIBLE(page) ((page & TT_AF) != 0) - -/** - Check the page table for Read/Write/Execute regions. - - @param[in] Context Unit test context - - @retval UNIT_TEST_PASSED The unit test passed - @retval other The unit test failed - -**/ -UNIT_TEST_STATUS -EFIAPI -NoReadWriteExecute ( - IN UNIT_TEST_CONTEXT Context - ) -{ - UINT64 *Pml0; - UINT64 *Pte1G; - UINT64 *Pte2M; - UINT64 *Pte4K; - BOOLEAN FoundRWXAddress; - UINT64 Index3; - UINT64 Index2; - UINT64 Index1; - UINT64 Index0; - UINT64 RootEntryCount; - UINT64 Address; - - FoundRWXAddress = FALSE; - - Pml0 = (UINT64 *)ArmGetTTBR0BaseAddress (); - RootEntryCount = ROOT_TABLE_LEN (ArmGetTCR () & TCR_T0SZ_MASK); - - for (Index0 = 0x0; Index0 < RootEntryCount; Index0++) { - Index1 = 0; - Index2 = 0; - Index3 = 0; - - if (!IS_TABLE (Pml0[Index0], 0)) { - continue; - } - - // Level 0 must always be table entries - Pte1G = (UINT64 *)(Pml0[Index0] & TT_ADDRESS_MASK); - - for (Index1 = 0x0; Index1 < TT_ENTRY_COUNT; Index1++ ) { - Index2 = 0; - Index3 = 0; - - // If the entry is not valid, skip it - if ((Pte1G[Index1] & IS_VALID) == 0) { - continue; - } - - if (!IS_BLOCK (Pte1G[Index1], 1)) { - // This is a table - Pte2M = (UINT64 *)(Pte1G[Index1] & TT_ADDRESS_MASK); - - for (Index2 = 0x0; Index2 < TT_ENTRY_COUNT; Index2++ ) { - Index3 = 0; - - // If the entry is not valid, skip it - if ((Pte2M[Index2] & IS_VALID) == 0) { - continue; - } - - if (!IS_BLOCK (Pte2M[Index2], 2)) { - // This is a table - Pte4K = (UINT64 *)(Pte2M[Index2] & TT_ADDRESS_MASK); - - for (Index3 = 0x0; Index3 < TT_ENTRY_COUNT; Index3++ ) { - // If the entry is not valid, skip it - if ((Pte4K[Index3] & IS_VALID) == 0) { - continue; - } - - // This is a block - if (IS_READ_WRITE (Pte4K[Index3]) && // Read/Write - IS_EXECUTABLE (Pte4K[Index3]) && // Execute - IS_ACCESSIBLE (Pte4K[Index3])) // Access Flag (0 for guard pages) - { - Address = IndexToAddress (Index0, Index1, Index2, Index3); - - if (!CanRegionBeRWX (Address, SIZE_4KB)) { - UT_LOG_ERROR ("Memory Range 0x%llx-0x%llx is Read/Write/Execute\n", Address, Address + SIZE_4KB); - FoundRWXAddress = TRUE; - } - } - } - } else { - // This is an block - if (IS_READ_WRITE (Pte2M[Index2]) && // Read/Write - IS_EXECUTABLE (Pte2M[Index2]) && // Execute - IS_ACCESSIBLE (Pte2M[Index2])) // Access Flag (0 for guard pages) - { - Address = IndexToAddress (Index0, Index1, Index2, Index3); - - if (!CanRegionBeRWX (Address, SIZE_2MB)) { - UT_LOG_ERROR ("Memory Range 0x%llx-0x%llx is Read/Write/Execute\n", Address, Address + SIZE_2MB); - FoundRWXAddress = TRUE; - } - } - } - } - } else { - // This is an block - if (IS_READ_WRITE (Pte1G[Index1]) && // Read/Write - IS_EXECUTABLE (Pte1G[Index1]) && // Execute - IS_ACCESSIBLE (Pte1G[Index1])) // Access Flag (0 for guard pages) - { - Address = IndexToAddress (Index0, Index1, Index2, Index3); - - if (!CanRegionBeRWX (Address, SIZE_1GB)) { - UT_LOG_ERROR ("Memory Range 0x%llx-0x%llx is Read/Write/Execute\n", Address, Address + SIZE_1GB); - FoundRWXAddress = TRUE; - } - } - } - } - } - - UT_ASSERT_FALSE (FoundRWXAddress); - - return UNIT_TEST_PASSED; -} diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c index a21d009c2e..cf1b869906 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c +++ b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.c @@ -7,13 +7,18 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ -#include "DxePagingAuditTestApp.h" +#include "../../PagingAuditCommon.h" #include #include #include +#include +#include + #include #include +#include +#include #define UNIT_TEST_APP_NAME "Paging Audit Test" #define UNIT_TEST_APP_VERSION "1" @@ -31,6 +36,67 @@ IMAGE_RANGE_DESCRIPTOR *mNonProtectedImageList = NULL; UINTN mSpecialRegionCount = 0; EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mMemorySpaceMap = NULL; UINTN mMemorySpaceMapCount = 0; +PAGE_MAP mMap = { 0 }; + +/** + Frees the entries in the mMap global. + + @param[in] Context Unit test context. +**/ +STATIC +VOID +EFIAPI +FreePageTableMap ( + IN UNIT_TEST_CONTEXT Context + ) +{ + if (mMap.Entries != NULL) { + FreePages (mMap.Entries, mMap.EntryPagesAllocated); + } +} + +/** + Populate the global flat page table map. + + @param[in] Context Unit test context. + + @retval EFI_SUCCESS The page table is parsed successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the page table map. + @retval EFI_INVALID_PARAMETER An error occurred while parsing the page table. +**/ +STATIC +UNIT_TEST_STATUS +EFIAPI +PopulatePageTableMap ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + + Status = CreateFlatPageTable (&mMap); + + while (Status == RETURN_BUFFER_TOO_SMALL) { + if ((mMap.Entries != NULL) && (mMap.EntryPagesAllocated > 0)) { + FreePages (mMap.Entries, mMap.EntryPagesAllocated); + } + + mMap.EntryPagesAllocated = EFI_SIZE_TO_PAGES (mMap.EntryCount * sizeof (PAGE_MAP_ENTRY)); + mMap.Entries = AllocatePages (mMap.EntryPagesAllocated); + + if (mMap.Entries == NULL) { + UT_LOG_ERROR ("Failed to allocate %d pages for page table map!\n", mMap.EntryPagesAllocated); + return UNIT_TEST_ERROR_PREREQUISITE_NOT_MET; + } + + Status = CreateFlatPageTable (&mMap); + } + + if ((Status != EFI_SUCCESS) && (mMap.Entries != NULL)) { + FreePageTableMap (Context); + } + + return Status == EFI_SUCCESS ? UNIT_TEST_PASSED : UNIT_TEST_ERROR_PREREQUISITE_NOT_MET; +} /** Populates the non protected image list global @@ -114,6 +180,7 @@ GetSpecialRegions ( @retval TRUE The region is allowed to be read/write/execute @retval FALSE The region is not allowed to be read/write/execute **/ +STATIC BOOLEAN CanRegionBeRWX ( IN UINT64 Address, @@ -179,6 +246,51 @@ CanRegionBeRWX ( return FALSE; } +/** + Check the page table for Read/Write/Execute regions. + + @param[in] Context Unit test context + + @retval UNIT_TEST_PASSED The unit test passed + @retval other The unit test failed + +**/ +UNIT_TEST_STATUS +EFIAPI +NoReadWriteExecute ( + IN UNIT_TEST_CONTEXT Context + ) +{ + UINTN Index; + BOOLEAN FoundRWXAddress; + + UT_ASSERT_NOT_NULL (mMap.Entries); + UT_ASSERT_NOT_EQUAL (mMap.EntryCount, 0); + + Index = 0; + FoundRWXAddress = FALSE; + + for ( ; Index < mMap.EntryCount; Index++) { + if (IsPageExecutable (mMap.Entries[Index].PageEntry) && + IsPageReadable (mMap.Entries[Index].PageEntry) && + IsPageWritable (mMap.Entries[Index].PageEntry)) + { + if (!CanRegionBeRWX (mMap.Entries[Index].LinearAddress, mMap.Entries[Index].Length)) { + UT_LOG_ERROR ( + "Memory Range 0x%llx-0x%llx is Read/Write/Execute\n", + mMap.Entries[Index].LinearAddress, + mMap.Entries[Index].LinearAddress + mMap.Entries[Index].Length + ); + FoundRWXAddress = TRUE; + } + } + } + + UT_ASSERT_FALSE (FoundRWXAddress); + + return UNIT_TEST_PASSED; +} + /** Locates and opens the SFS volume containing the application and, if successful, returns an @@ -401,7 +513,7 @@ DxePagingAuditTestAppEntryPoint ( DEBUG ((DEBUG_ERROR, "%a - Unable to fetch the GCD memory map. Test results may be inaccurate. Status: %r\n", __FUNCTION__, Status)); } - AddTestCase (Misc, "No pages can be read,write,execute", "Security.Misc.NoReadWriteExecute", NoReadWriteExecute, NULL, NULL, NULL); + AddTestCase (Misc, "No pages can be read,write,execute", "Security.Misc.NoReadWriteExecute", NoReadWriteExecute, PopulatePageTableMap, FreePageTableMap, NULL); // // Execute the tests. diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.h b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.h deleted file mode 100644 index 57e94839c6..0000000000 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/DxePagingAuditTestApp.h +++ /dev/null @@ -1,45 +0,0 @@ -/** @file -- DxePagingAuditTestApp.h -This Shell App tests the page table or writes page table and -memory map information to SFS - -Copyright (c) Microsoft Corporation. -SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include "../../PagingAuditCommon.h" - -#include -#include -#include - -/** - Check the page table for Read/Write/Execute regions. - - @param[in] Context Unit test context - - @retval UNIT_TEST_PASSED The unit test passed - @retval other The unit test failed - -**/ -UNIT_TEST_STATUS -EFIAPI -NoReadWriteExecute ( - IN UNIT_TEST_CONTEXT Context - ); - -/** - Checks if a region is allowed to be read/write/execute based on the special region array - and non protected image list - - @param[in] Address Start address of the region - @param[in] Length Length of the region - - @retval TRUE The region is allowed to be read/write/execute - @retval FALSE The region is not allowed to be read/write/execute -**/ -BOOLEAN -CanRegionBeRWX ( - IN UINT64 Address, - IN UINT64 Length - ); diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/X64/DxePagingAuditTests.c b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/X64/DxePagingAuditTests.c deleted file mode 100644 index fbce0784c5..0000000000 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/Dxe/App/X64/DxePagingAuditTests.c +++ /dev/null @@ -1,79 +0,0 @@ -/** @file -- DxePagingAuditTests.c - X64 implementations for DXE paging audit tests - - Copyright (c) Microsoft Corporation. - SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include -#include - -#include "../DxePagingAuditTestApp.h" - -/** - Check the page table for Read/Write/Execute regions. - - @param[in] Context Unit test context - - @retval UNIT_TEST_PASSED The unit test passed - @retval other The unit test failed - -**/ -UNIT_TEST_STATUS -EFIAPI -NoReadWriteExecute ( - IN UNIT_TEST_CONTEXT Context - ) -{ - IA32_MAP_ENTRY *Map; - UINTN MapCount; - UINTN Index; - BOOLEAN FoundRWXAddress; - IA32_CR4 Cr4; - PAGING_MODE PagingMode; - UINTN PagesAllocated = 0; - EFI_STATUS Status; - - Map = NULL; - MapCount = 0; - Index = 0; - FoundRWXAddress = FALSE; - - // Poll CR4 to deterimine the page table depth - Cr4.UintN = AsmReadCr4 (); - - if (Cr4.Bits.LA57 != 0) { - PagingMode = Paging5Level; - } else { - PagingMode = Paging4Level; - } - - // CR3 is the page table pointer - Status = PageTableParse (AsmReadCr3 (), PagingMode, NULL, &MapCount); - - while (Status == RETURN_BUFFER_TOO_SMALL) { - if ((Map != NULL) && (PagesAllocated > 0)) { - FreePages (Map, PagesAllocated); - } - - PagesAllocated = EFI_SIZE_TO_PAGES (MapCount * sizeof (IA32_MAP_ENTRY)); - Map = AllocatePages (PagesAllocated); - - UT_ASSERT_NOT_NULL (Map); - Status = PageTableParse (AsmReadCr3 (), PagingMode, Map, &MapCount); - } - - for ( ; Index < MapCount; Index++) { - if ((Map[Index].Attribute.Bits.ReadWrite != 0) && (Map[Index].Attribute.Bits.Nx == 0)) { - if (!CanRegionBeRWX (Map[Index].LinearAddress, Map[Index].Length)) { - UT_LOG_ERROR ("Memory Range 0x%llx-0x%llx is Read/Write/Execute\n", Map[Index].LinearAddress, Map[Index].LinearAddress + Map[Index].Length); - FoundRWXAddress = TRUE; - } - } - } - - UT_ASSERT_FALSE (FoundRWXAddress); - - return UNIT_TEST_PASSED; -} diff --git a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditTestApp.inf b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditTestApp.inf index f5c30cc8a6..0ed078d09e 100644 --- a/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditTestApp.inf +++ b/UefiTestingPkg/AuditTests/PagingAudit/UEFI/DxePagingAuditTestApp.inf @@ -18,17 +18,14 @@ [Sources] Dxe/App/DxePagingAuditTestApp.c - Dxe/App/DxePagingAuditTestApp.h PagingAuditCommon.c PagingAuditCommon.h [Sources.X64] X64/PagingAuditProcessor.c - Dxe/App/X64/DxePagingAuditTests.c [Sources.AARCH64] AArch64/PagingAuditProcessor.c - Dxe/App/AArch64/DxePagingAuditTests.c [Packages.AARCH64] ArmPkg/ArmPkg.dec @@ -53,6 +50,7 @@ UnitTestLib DxeMemoryProtectionHobLib FileHandleLib + FlatPageTableLib [LibraryClasses.AARCH64] ArmLib