From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.31; helo=mga06.intel.com; envelope-from=jian.j.wang@intel.com; receiver=edk2-devel@lists.01.org Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 8CB8621B00DC4 for ; Wed, 29 Nov 2017 00:42:20 -0800 (PST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 29 Nov 2017 00:46:44 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.44,472,1505804400"; d="scan'208";a="13253647" Received: from jwang36-mobl2.ccr.corp.intel.com ([10.239.192.50]) by orsmga002.jf.intel.com with ESMTP; 29 Nov 2017 00:46:43 -0800 From: Jian J Wang To: edk2-devel@lists.01.org Cc: Jiewen Yao , Eric Dong , Laszlo Ersek Date: Wed, 29 Nov 2017 16:46:39 +0800 Message-Id: <20171129084640.20076-2-jian.j.wang@intel.com> X-Mailer: git-send-email 2.14.1.windows.1 In-Reply-To: <20171129084640.20076-1-jian.j.wang@intel.com> References: <20171129084640.20076-1-jian.j.wang@intel.com> Subject: [PATCH 1/2] UefiCpuPkg/CpuDxe: Check CR0.WP before changing page table X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 29 Nov 2017 08:42:20 -0000 The CPU driver will always set CR0.WP if paging is enabled. GetCurrentPagingContext(): if ((AsmReadCr0 () & BIT31) != 0) { PagingContext->ContextData.X64.PageTableBase = (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64); if ((AsmReadCr0 () & BIT16) == 0) { AsmWriteCr0 (AsmReadCr0 () | BIT16); SyncMemoryPageAttributesAp (SyncCpuEnableWriteProtection); } } else { Before this patch, there's no driver to set page attribute of memory used for page table to be "read-only". CR0.WP will not prevent the page attributes from updating. Since this patch, the pages used for page table will be set as "read-only" to protect them from corruption caused by buffer overflow issue. In this situation, CR0.WP must be cleared before updating page table. CR0.WP must be set again afterwards. Cc: Jiewen Yao Cc: Eric Dong Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jian J Wang --- UefiCpuPkg/CpuDxe/CpuPageTable.c | 65 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c index 9658ed74c5..dd0debb448 100644 --- a/UefiCpuPkg/CpuDxe/CpuPageTable.c +++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c @@ -561,6 +561,43 @@ SplitPage ( } } +/** + Check the WP status in CR0 register. This bit is used to lock or unlock write + access to pages marked as read-only. + + @retval TRUE Write protection is enabled. + @retval FALSE Write protection is disabled. +**/ +BOOLEAN +IsReadOnlyPageWriteProtected ( + VOID + ) +{ + return ((AsmReadCr0 () & BIT16) != 0); +} + +/** + Disable Write Protect on pages marked as read-only. +**/ +VOID +DisableReadOnlyPageWriteProtect ( + VOID + ) +{ + AsmWriteCr0 (AsmReadCr0() & ~BIT16); +} + +/** + Enable Write Protect on pages marked as read-only. +**/ +VOID +EnableReadOnlyPageWriteProtect ( + VOID + ) +{ + AsmWriteCr0 (AsmReadCr0() | BIT16); +} + /** This function modifies the page attributes for the memory region specified by BaseAddress and Length from their current attributes to the attributes specified by Attributes. @@ -609,6 +646,7 @@ ConvertMemoryPageAttributes ( PAGE_ATTRIBUTE SplitAttribute; RETURN_STATUS Status; BOOLEAN IsEntryModified; + BOOLEAN IsWpEnabled; if ((BaseAddress & (SIZE_4KB - 1)) != 0) { DEBUG ((DEBUG_ERROR, "BaseAddress(0x%lx) is not aligned!\n", BaseAddress)); @@ -666,13 +704,23 @@ ConvertMemoryPageAttributes ( *IsModified = FALSE; } + // + // Make sure that the page table is changeable. + // + IsWpEnabled = IsReadOnlyPageWriteProtected (); + if (IsWpEnabled) { + DisableReadOnlyPageWriteProtect (); + } + // // Below logic is to check 2M/4K page to make sure we donot waist memory. // + Status = EFI_SUCCESS; while (Length != 0) { PageEntry = GetPageTableEntry (&CurrentPagingContext, BaseAddress, &PageAttribute); if (PageEntry == NULL) { - return RETURN_UNSUPPORTED; + Status = RETURN_UNSUPPORTED; + goto Done; } PageEntryLength = PageAttributeToLength (PageAttribute); SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute); @@ -690,11 +738,13 @@ ConvertMemoryPageAttributes ( Length -= PageEntryLength; } else { if (AllocatePagesFunc == NULL) { - return RETURN_UNSUPPORTED; + Status = RETURN_UNSUPPORTED; + goto Done; } Status = SplitPage (PageEntry, PageAttribute, SplitAttribute, AllocatePagesFunc); if (RETURN_ERROR (Status)) { - return RETURN_UNSUPPORTED; + Status = RETURN_UNSUPPORTED; + goto Done; } if (IsSplitted != NULL) { *IsSplitted = TRUE; @@ -709,7 +759,14 @@ ConvertMemoryPageAttributes ( } } - return RETURN_SUCCESS; +Done: + // + // Restore page table write protection, if any. + // + if (IsWpEnabled) { + EnableReadOnlyPageWriteProtect (); + } + return Status; } /** -- 2.14.1.windows.1