From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.4642.1671159679427236019 for ; Thu, 15 Dec 2022 19:01:28 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=mXy8qe2M; spf=pass (domain: intel.com, ip: 192.55.52.136, mailfrom: dun.tan@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1671159688; x=1702695688; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=OETzare8rBWyD+j+7wF6o9Y91bUzck5e3ZSBTcCcLj4=; b=mXy8qe2MFvPGQB2IgichQm+JVLGoQQUaMhBtNi3wEA23adTPZJA6xAD7 w1Y0n3Yo7n/S/S75yb22F3sj7OnjsC4G+v8N09YPaANUortGxj9vSDxPv qMNX085RYd0lIcRpCt/QSDYI1f7TUkjx+AL2gNWH6i9mqRcpdSZm3iGrv /n0pGfENWv3kODiYEzIUZK/zyf5xnukl0guaCHFejUdmvE0P9YpwGFE37 ftmu4ZFHXFXe29DrDwIhXCVfsA8JeM24ivtDNb64zWSTyvZ7gboM7J3F0 ngBtnicRJBOcORx2JmXgHIChLwFlaQ9OnUEA/6sn/cX/K5cvhtm1w9ig2 w==; X-IronPort-AV: E=McAfee;i="6500,9779,10562"; a="298537825" X-IronPort-AV: E=Sophos;i="5.96,248,1665471600"; d="scan'208";a="298537825" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2022 19:01:28 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10562"; a="599793692" X-IronPort-AV: E=Sophos;i="5.96,248,1665471600"; d="scan'208";a="599793692" Received: from shwdeopenlab702.ccr.corp.intel.com ([10.239.182.152]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2022 19:01:26 -0800 From: "duntan" To: devel@edk2.groups.io Cc: Eric Dong , Ray Ni , Rahul Kumar Subject: [PATCH 3/3] UefiCpuPkg: Simplify the code to set smm page table as RO Date: Fri, 16 Dec 2022 11:00:59 +0800 Message-Id: <20221216030059.1373-4-dun.tan@intel.com> X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: <20221216030059.1373-1-dun.tan@intel.com> References: <20221216030059.1373-1-dun.tan@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Simplify the code to set memory used by smm page table as RO. Since memory used by smm page table are in PageTablePool list, we only need to set all PageTablePool as ReadOnly in smm page table itself. Also, we only need to flush tlb once after setting all page table pool as Read Only. Signed-off-by: Dun Tan Cc: Eric Dong Cc: Ray Ni Cc: Rahul Kumar --- UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 123 --------------------------------------------------------------------------------------------------------------------------- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 19 ++++++++++++++++++- UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 170 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 files changed, 152 insertions(+), 294 deletions(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c index 26efa71eff..26bbba77b0 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c @@ -10,24 +10,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include "PiSmmCpuDxeSmm.h" -/** - Disable CET. -**/ -VOID -EFIAPI -DisableCet ( - VOID - ); - -/** - Enable CET. -**/ -VOID -EFIAPI -EnableCet ( - VOID - ); - /** Create PageTable for SMM use. @@ -221,111 +203,6 @@ Exit: } /** - This function sets memory attribute for page table. -**/ -VOID -SetPageTableAttributes ( - VOID - ) -{ - UINTN Index2; - UINTN Index3; - UINT64 *L1PageTable; - UINT64 *L2PageTable; - UINT64 *L3PageTable; - UINTN PageTableBase; - BOOLEAN IsSplitted; - BOOLEAN PageTableSplitted; - BOOLEAN CetEnabled; - - // - // Don't mark page table to read-only if heap guard is enabled. - // - // BIT2: SMM page guard enabled - // BIT3: SMM pool guard enabled - // - if ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) { - DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as heap guard is enabled\n")); - return; - } - - // - // Don't mark page table to read-only if SMM profile is enabled. - // - if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { - DEBUG ((DEBUG_INFO, "Don't mark page table to read-only as SMM profile is enabled\n")); - return; - } - - DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n")); - - // - // Disable write protection, because we need mark page table to be write protected. - // We need *write* page table memory, to mark itself to be *read only*. - // - CetEnabled = ((AsmReadCr4 () & CR4_CET_ENABLE) != 0) ? TRUE : FALSE; - if (CetEnabled) { - // - // CET must be disabled if WP is disabled. - // - DisableCet (); - } - - AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP); - - do { - DEBUG ((DEBUG_INFO, "Start...\n")); - PageTableSplitted = FALSE; - - PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64; - L3PageTable = (UINT64 *)PageTableBase; - - SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)PageTableBase, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - - for (Index3 = 0; Index3 < 4; Index3++) { - L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); - if (L2PageTable == NULL) { - continue; - } - - SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - - for (Index2 = 0; Index2 < SIZE_4KB/sizeof (UINT64); Index2++) { - if ((L2PageTable[Index2] & IA32_PG_PS) != 0) { - // 2M - continue; - } - - L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); - if (L1PageTable == NULL) { - continue; - } - - SmmSetMemoryAttributesEx (PageTableBase, FALSE, (EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - } - } - } while (PageTableSplitted); - - // - // Enable write protection, after page table updated. - // - AsmWriteCr0 (AsmReadCr0 () | CR0_WP); - if (CetEnabled) { - // - // re-enable CET. - // - EnableCet (); - } - mIsReadOnlyPageTable = TRUE; - - return; -} - -/** - This function returns with no action for 32 bit. @param[out] *Cr2 Pointer to variable to hold CR2 register value. **/ diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index a0daaa1900..5f0a38e400 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -260,7 +260,6 @@ extern UINTN mNumberOfCpus; extern EFI_SMM_CPU_PROTOCOL mSmmCpu; extern EFI_MM_MP_PROTOCOL mSmmMp; extern BOOLEAN m5LevelPagingNeeded; -extern BOOLEAN mIsReadOnlyPageTable; /// /// The mode of the CPU at the time an SMI occurs @@ -279,6 +278,24 @@ typedef struct { UINTN FreePages; } PAGE_TABLE_POOL; +/** + Disable CET. +**/ +VOID +EFIAPI +DisableCet ( + VOID + ); + +/** + Enable CET. +**/ +VOID +EFIAPI +EnableCet ( + VOID + ); + // // SMM CPU Protocol function prototypes. // diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c index 8f0c6410e6..9f091c6485 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c @@ -1738,3 +1738,137 @@ EdkiiSmmGetMemoryAttributes ( return EFI_SUCCESS; } + +/** + Prevent the memory pages used for SMM page table from been overwritten. +**/ +VOID +EnablePageTableProtection ( + VOID + ) +{ + PAGE_TABLE_POOL *HeadPool; + PAGE_TABLE_POOL *Pool; + UINT64 PoolSize; + EFI_PHYSICAL_ADDRESS Address; + UINTN PageTableBase; + + if (mPageTablePool == NULL) { + return; + } + + PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64; + + // + // ConvertMemoryPageAttributes might update mPageTablePool. It's safer to + // remember original one in advance. + // + HeadPool = mPageTablePool; + Pool = HeadPool; + do { + Address = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool & PAGE_TABLE_POOL_ALIGN_MASK; + PoolSize = Pool->Offset + EFI_PAGES_TO_SIZE (Pool->FreePages); + + ConvertMemoryPageAttributes (PageTableBase, m5LevelPagingNeeded, Address, PoolSize, EFI_MEMORY_RO, TRUE, NULL, NULL); + Pool = Pool->NextPool; + } while (Pool != HeadPool); +} + +/** + Return whether memory used by SMM page table need to be set as Read Only. + + @retval TRUE Need to set SMM page table as Read Only. + @retval FALSE Do not set SMM page table as Read Only. +**/ +BOOLEAN +IfReadOnlyPageTableNeeded ( + VOID + ) +{ + // + // Don't mark page table memory as read-only if + // - no restriction on access to non-SMRAM memory; or + // - SMM heap guard feature enabled; or + // BIT2: SMM page guard enabled + // BIT3: SMM pool guard enabled + // - SMM profile feature enabled + // + if (!IsRestrictedMemoryAccess () || + ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) || + FeaturePcdGet (PcdCpuSmmProfileEnable)) + { + if (sizeof (UINTN) == sizeof (UINT64)) { + // + // Restriction on access to non-SMRAM memory and heap guard could not be enabled at the same time. + // + ASSERT ( + !(IsRestrictedMemoryAccess () && + (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) + ); + + // + // Restriction on access to non-SMRAM memory and SMM profile could not be enabled at the same time. + // + ASSERT (!(IsRestrictedMemoryAccess () && FeaturePcdGet (PcdCpuSmmProfileEnable))); + } + + return FALSE; + } + + return TRUE; +} + +/** + This function sets memory attribute for page table. +**/ +VOID +SetPageTableAttributes ( + VOID + ) +{ + BOOLEAN CetEnabled; + + if (!IfReadOnlyPageTableNeeded ()) { + return; + } + + DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n")); + + // + // Disable write protection, because we need mark page table to be write protected. + // We need *write* page table memory, to mark itself to be *read only*. + // + CetEnabled = ((AsmReadCr4 () & CR4_CET_ENABLE) != 0) ? TRUE : FALSE; + if (CetEnabled) { + // + // CET must be disabled if WP is disabled. + // + DisableCet (); + } + + AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP); + + // Set memory used by page table as Read Only. + DEBUG ((DEBUG_INFO, "Start...\n")); + EnablePageTableProtection (); + + // + // Enable write protection, after page table attribute updated. + // + AsmWriteCr0 (AsmReadCr0 () | CR0_WP); + mIsReadOnlyPageTable = TRUE; + + // + // Flush TLB after mark all page table pool as read only. + // + FlushTlbForAll (); + + if (CetEnabled) { + // + // re-enable CET. + // + EnableCet (); + } + + return; +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c index d714ca5b5a..3deb1ffd67 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c @@ -20,24 +20,6 @@ BOOLEAN m1GPageTableSupport = FALSE; BOOLEAN mCpuSmmRestrictedMemoryAccess; X86_ASSEMBLY_PATCH_LABEL gPatch5LevelPagingNeeded; -/** - Disable CET. -**/ -VOID -EFIAPI -DisableCet ( - VOID - ); - -/** - Enable CET. -**/ -VOID -EFIAPI -EnableCet ( - VOID - ); - /** Check if 1-GByte pages is supported by processor or not. @@ -1157,158 +1139,6 @@ Exit: ReleaseSpinLock (mPFLock); } -/** - This function sets memory attribute for page table. -**/ -VOID -SetPageTableAttributes ( - VOID - ) -{ - UINTN Index2; - UINTN Index3; - UINTN Index4; - UINTN Index5; - UINT64 *L1PageTable; - UINT64 *L2PageTable; - UINT64 *L3PageTable; - UINT64 *L4PageTable; - UINT64 *L5PageTable; - UINTN PageTableBase; - BOOLEAN IsSplitted; - BOOLEAN PageTableSplitted; - BOOLEAN CetEnabled; - BOOLEAN Enable5LevelPaging; - IA32_CR4 Cr4; - - // - // Don't mark page table memory as read-only if - // - no restriction on access to non-SMRAM memory; or - // - SMM heap guard feature enabled; or - // BIT2: SMM page guard enabled - // BIT3: SMM pool guard enabled - // - SMM profile feature enabled - // - if (!mCpuSmmRestrictedMemoryAccess || - ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) || - FeaturePcdGet (PcdCpuSmmProfileEnable)) - { - // - // Restriction on access to non-SMRAM memory and heap guard could not be enabled at the same time. - // - ASSERT ( - !(mCpuSmmRestrictedMemoryAccess && - (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) - ); - - // - // Restriction on access to non-SMRAM memory and SMM profile could not be enabled at the same time. - // - ASSERT (!(mCpuSmmRestrictedMemoryAccess && FeaturePcdGet (PcdCpuSmmProfileEnable))); - return; - } - - DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n")); - - // - // Disable write protection, because we need mark page table to be write protected. - // We need *write* page table memory, to mark itself to be *read only*. - // - CetEnabled = ((AsmReadCr4 () & CR4_CET_ENABLE) != 0) ? TRUE : FALSE; - if (CetEnabled) { - // - // CET must be disabled if WP is disabled. - // - DisableCet (); - } - - AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP); - - do { - DEBUG ((DEBUG_INFO, "Start...\n")); - PageTableSplitted = FALSE; - L5PageTable = NULL; - - PageTableBase = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64; - Cr4.UintN = AsmReadCr4 (); - Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1); - - if (Enable5LevelPaging) { - L5PageTable = (UINT64 *)PageTableBase; - SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)PageTableBase, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - } - - for (Index5 = 0; Index5 < (Enable5LevelPaging ? SIZE_4KB/sizeof (UINT64) : 1); Index5++) { - if (Enable5LevelPaging) { - L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); - if (L4PageTable == NULL) { - continue; - } - } else { - L4PageTable = (UINT64 *)PageTableBase; - } - - SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - - for (Index4 = 0; Index4 < SIZE_4KB/sizeof (UINT64); Index4++) { - L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); - if (L3PageTable == NULL) { - continue; - } - - SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - - for (Index3 = 0; Index3 < SIZE_4KB/sizeof (UINT64); Index3++) { - if ((L3PageTable[Index3] & IA32_PG_PS) != 0) { - // 1G - continue; - } - - L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); - if (L2PageTable == NULL) { - continue; - } - - SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - - for (Index2 = 0; Index2 < SIZE_4KB/sizeof (UINT64); Index2++) { - if ((L2PageTable[Index2] & IA32_PG_PS) != 0) { - // 2M - continue; - } - - L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); - if (L1PageTable == NULL) { - continue; - } - - SmmSetMemoryAttributesEx (PageTableBase, Enable5LevelPaging, (EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); - PageTableSplitted = (PageTableSplitted || IsSplitted); - } - } - } - } - } while (PageTableSplitted); - - // - // Enable write protection, after page table updated. - // - AsmWriteCr0 (AsmReadCr0 () | CR0_WP); - if (CetEnabled) { - // - // re-enable CET. - // - EnableCet (); - } - mIsReadOnlyPageTable = TRUE; - - return; -} - /** This function reads CR2 register when on-demand paging is enabled. -- 2.31.1.windows.1