From nobody Tue Apr 16 09:46:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+83540+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+83540+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1636522470; cv=none; d=zohomail.com; s=zohoarc; b=ia6mZcK5eu5gD+Q6wflOfv8LCuqHpJLgdFimqLepuZrJGxZnw2X3jbK+XfCxqGnsA/B9N+of2Xhid/ms7LW94ksVjzxLbpYtAIzxk/1pxw788EQ/8HlJOQWlq5jrxP4tFIi3uMQSnrW9RwnAIeiLORap0CnCFzPrfEycf6o8DBE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1636522470; h=Cc:Date:From:List-Subscribe:List-Id:List-Help:List-Unsubscribe:Message-ID:Reply-To:Sender:Subject:To; bh=/Qg1V+XT2+QVSRqXCPxr/3OAiXAIt8AdMXHrcZVbfBA=; b=DQw6Od8BK6kLVqAqqr4Rry+3+RNt5hCiGg4B8y2MKv+k7jID1MoCAn39kxQlFX+66oFy2L3t5wClK9O+TraPDt3/f8mynLNJq5Qs11kD6sbSv422yA8qAIrtzAbJjiFLcn5/MCTVjN8B1Gu9uYkaYoikGP+qomkvU/3qrZKvCjs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+83540+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1636522470906880.4498996018885; Tue, 9 Nov 2021 21:34:30 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id uaszYY1788612xdTQpc0V0ab; Tue, 09 Nov 2021 21:34:30 -0800 X-Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mx.groups.io with SMTP id smtpd.web09.8330.1636522469510691530 for ; Tue, 09 Nov 2021 21:34:29 -0800 X-IronPort-AV: E=McAfee;i="6200,9189,10163"; a="232552473" X-IronPort-AV: E=Sophos;i="5.87,222,1631602800"; d="scan'208";a="232552473" X-Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Nov 2021 21:34:28 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.87,222,1631602800"; d="scan'208";a="503822072" X-Received: from shwdesssddpdwei.ccr.corp.intel.com ([10.239.157.43]) by orsmga008.jf.intel.com with ESMTP; 09 Nov 2021 21:34:26 -0800 From: "Sheng Wei" To: devel@edk2.groups.io Cc: Eric Dong , Ray Ni , Rahul Kumar Subject: [edk2-devel] [PATCH] UefiCpuPkg/PiSmmCpuDxeSmm: Use SMM Interrupt Shadow Stack Date: Wed, 10 Nov 2021 13:34:21 +0800 Message-Id: <20211110053421.19880-1-w.sheng@intel.com> Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,w.sheng@intel.com X-Gm-Message-State: yChQoMoQJSIpnFr52GeB4vf2x1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1636522470; bh=OgS6UzXjkIYUbxpdXbaonQG1qaP+vsn1W/QAboQMuCA=; h=Cc:Date:From:Reply-To:Subject:To; b=YI1ozo8ZHGlTFn6zVGpAjSQdq0CanpgZdyfJaXqeGEVuix9r10DjLgLOKOBX9YR9x51 UrcZQri9NEwSyP6dvu4M6wq3iGaZfYXs5EP87vjQw7Zv54ADPH26st8iZc+BA+eeaB6HU 5ElF6joO2zm9pu89ILVl4i28qQoHF65vOoI= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1636522472686100002 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" When CET shadow stack feature is enabled, it needs to use IST for the exceptions, and uses interrupt shadow stack for the stack switch. Shadow stack should be 32 bytes aligned. Check IST field, when clear shadow stack token busy bit when using retf. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3728 Signed-off-by: Sheng Wei Cc: Eric Dong Cc: Ray Ni Cc: Rahul Kumar Signed-off-by: Sheng Wei --- .../X64/Xcode5ExceptionHandlerAsm.nasm | 45 ++++++----- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 23 +++++- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 10 +++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 7 ++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c | 94 +++++++++++++++---= ---- 5 files changed, 131 insertions(+), 48 deletions(-) diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionH= andlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5Except= ionHandlerAsm.nasm index 4881a02848..14e5c2f8dd 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerA= sm.nasm +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerA= sm.nasm @@ -25,7 +25,6 @@ extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag extern ASM_PFX(CommonExceptionHandler) -extern ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard)) =20 SECTION .data =20 @@ -282,42 +281,50 @@ DrFinish: =20 ; The follow algorithm is used for clear shadow stack token busy bit. ; The comment is based on the sample shadow stack. + ; Shadow stack is 32 bytes aligned. ; The sample shadow stack layout : ; Address | Context ; +-------------------------+ - ; 0xFD0 | FREE | it is 0xFD8|0x02|(LMA & CS.L), a= fter SAVEPREVSSP. + ; 0xFB8 | FREE | It is 0xFC0|0x02|(LMA & CS.L), a= fter SAVEPREVSSP. ; +-------------------------+ - ; 0xFD8 | Prev SSP | + ; 0xFC0 | Prev SSP | ; +-------------------------+ - ; 0xFE0 | RIP | + ; 0xFC8 | RIP | ; +-------------------------+ - ; 0xFE8 | CS | + ; 0xFD0 | CS | ; +-------------------------+ - ; 0xFF0 | 0xFF0 | BUSY | BUSY flag cleared after CLRSSBSY + ; 0xFD8 | 0xFD8 | BUSY | BUSY flag cleared after CLRSSBSY ; +-------------------------+ - ; 0xFF8 | 0xFD8|0x02|(LMA & CS.L) | + ; 0xFE0 | 0xFC0|0x02|(LMA & CS.L) | ; +-------------------------+ ; Instructions for Intel Control Flow Enforcement Technology (CET) are= supported since NASM version 2.15.01. cmp qword [ASM_PFX(mDoFarReturnFlag)], 0 jz CetDone - cmp qword [rbp + 8], PF_EXCEPTION ; check if it is a Page Fault - jnz CetDone - cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0 - jz CetDone mov rax, cr4 - and rax, 0x800000 ; check if CET is enabled + and rax, 0x800000 ; Check if CET is enabled + jz CetDone + sub rsp, 0x10 + sidt [rsp] + mov rcx, qword [rsp + 2]; Get IDT base address + add rsp, 0x10 + mov rax, qword [rbp + 8]; Get exception number + sal rax, 0x04 ; Get IDT offset + add rax, rcx + add rax, 0x04 ; Get IST field address + mov al, byte [rax] + and rax, 0x01 ; Check IST field jz CetDone - ; SSP should be 0xFD8 at this point + ; SSP should be 0xFC0 at this point mov rax, 0x04 ; advance past cs:lip:prevssp;supervisor s= hadow stack token - INCSSP_RAX ; After this SSP should be 0xFF8 - SAVEPREVSSP ; now the shadow stack restore token will = be created at 0xFD0 - READSSP_RAX ; Read new SSP, SSP should be 0x1000 + INCSSP_RAX ; After this SSP should be 0xFE0 + SAVEPREVSSP ; now the shadow stack restore token will = be created at 0xFB8 + READSSP_RAX ; Read new SSP, SSP should be 0xFE8 sub rax, 0x10 - CLRSSBSY_RAX ; Clear token at 0xFF0, SSP should be 0 af= ter this + CLRSSBSY_RAX ; Clear token at 0xFD8, SSP should be 0 af= ter this sub rax, 0x20 - RSTORSSP_RAX ; Restore to token at 0xFD0, new SSP will = be 0xFD0 + RSTORSSP_RAX ; Restore to token at 0xFB8, new SSP will = be 0xFB8 mov rax, 0x01 ; Pop off the new save token created - INCSSP_RAX ; SSP should be 0xFD8 now + INCSSP_RAX ; SSP should be 0xFC0 now CetDone: =20 cli diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmC= puDxeSmm/PiSmmCpuDxeSmm.c index 67ad9a4c07..ac0c901590 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -876,6 +876,21 @@ PiCpuSmmEntry ( mSmmShadowStackSize =3D 0; if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) !=3D 0) && mCetSup= ported) { // + // SMM Stack Guard Disabled + // 1 more pages is allocated for each processor, it is known good stac= k. + // Append Shadow Stack after normal stack with 1 more page as known go= od shadow stack. + // + // |=3D Stacks + // +-------------------------------------+----------------------------= ----------------------+ + // | Known Good Stack | SMM Stack | Known Good Shadow Stack | = SMM Shadow Stack | + // +-------------------------------------+----------------------------= ----------------------+ + // | |PcdCpuSmmStackSize| |Pc= dCpuSmmShadowStackSize| + // |<---------- mSmmStackSize ---------->|<--------------- mSmmShadowS= tackSize ------------>| + // | = | + // |<-------------------------------- Processor N --------------------= --------------------->| + // + // + // SMM Stack Guard Enabled // Append Shadow Stack after normal stack // // |=3D Stacks @@ -888,8 +903,14 @@ PiCpuSmmEntry ( // |<-------------------------------------------- Processor N --------= ----------------------------------------------->| // mSmmShadowStackSize =3D EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32= (PcdCpuSmmShadowStackSize))); + // + // Add 1 page as known good shadow stack + // + mSmmShadowStackSize +=3D EFI_PAGES_TO_SIZE (1); if (FeaturePcdGet (PcdCpuSmmStackGuard)) { - mSmmShadowStackSize +=3D EFI_PAGES_TO_SIZE (2); + mSmmShadowStackSize +=3D EFI_PAGES_TO_SIZE (1); + } else { + mSmmStackSize +=3D EFI_PAGES_TO_SIZE (1); } } =20 diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmC= puDxeSmm/PiSmmCpuDxeSmm.h index 2248a8c5ee..5fea45b342 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -557,6 +557,16 @@ InitializeIDTSmmStackGuard ( VOID ); =20 +/** + Initialize IDT for SMM Shadow Stack. + +**/ +VOID +EFIAPI +InitializeIDTSmmShadowStack ( + VOID + ); + /** Initialize Gdt for all processors. =20 diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuD= xeSmm/X64/PageTbl.c index d6f8dd94d3..71cf113aea 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c @@ -484,6 +484,13 @@ SmmInitPageTable ( InitializeIDTSmmStackGuard (); } =20 + // + // Additional SMM IDT initialization for SMM CET shadow stack + // + if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) !=3D 0) && mCetSup= ported) { + InitializeIDTSmmShadowStack (); + } + // // Return the address of PML4/PML5 (to set CR3) // diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c b/UefiCpuPkg/PiSm= mCpuDxeSmm/X64/SmmFuncsArch.c index ca3f5ff91a..436df41737 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c @@ -44,6 +44,37 @@ InitializeIDTSmmStackGuard ( IdtGate->Bits.Reserved_0 =3D 1; } =20 +/** + Initialize IDT for SMM Shadow Stack. + +**/ +VOID +EFIAPI +InitializeIDTSmmShadowStack ( + VOID + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtGate; + + DEBUG ((DEBUG_INFO, "InitializeIDTSmmShadowStack\n")); + + // + // If SMM Shadow Stack is enabled, set the IST field of + // the interrupt gate for Page Fault Exception to be 1 + // + IdtGate =3D (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base; + IdtGate +=3D EXCEPT_IA32_PAGE_FAULT; + IdtGate->Bits.Reserved_0 =3D 1; + + // + // If SMM Shadow Stack is enabled, set the IST field of + // the interrupt gate for Machine Check Exception to be 1 + // + IdtGate =3D (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base; + IdtGate +=3D EXCEPT_IA32_MACHINE_CHECK; + IdtGate->Bits.Reserved_0 =3D 1; +} + /** Initialize Gdt for all processors. =20 @@ -89,7 +120,7 @@ InitGdt ( GdtDescriptor->Bits.BaseMid =3D (UINT8)((UINTN)TssBase >> 16); GdtDescriptor->Bits.BaseHigh =3D (UINT8)((UINTN)TssBase >> 24); =20 - if (FeaturePcdGet (PcdCpuSmmStackGuard)) { + if ((FeaturePcdGet (PcdCpuSmmStackGuard)) || ((PcdGet32 (PcdControlFlo= wEnforcementPropertyMask) !=3D 0) && mCetSupported)) { // // Setup top of known good stack as IST1 for each processor. // @@ -177,8 +208,16 @@ InitShadowStack ( =20 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) !=3D 0) && mCetSup= ported) { SmmShadowStackSize =3D EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 = (PcdCpuSmmShadowStackSize))); + // + // Add 1 page as known good shadow stack + // + SmmShadowStackSize +=3D EFI_PAGES_TO_SIZE (1); + if (FeaturePcdGet (PcdCpuSmmStackGuard)) { - SmmShadowStackSize +=3D EFI_PAGES_TO_SIZE (2); + // + // Add one guard page between Known Good Shadow Stack and SMM Shadow= Stack. + // + SmmShadowStackSize +=3D EFI_PAGES_TO_SIZE (1); } mCetPl0Ssp =3D (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - size= of(UINT64)); PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4); @@ -186,33 +225,32 @@ InitShadowStack ( DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack)); DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSiz= e)); =20 - if (FeaturePcdGet (PcdCpuSmmStackGuard)) { - if (mSmmInterruptSspTables =3D=3D 0) { - mSmmInterruptSspTables =3D (UINTN)AllocateZeroPool(sizeof(UINT64) = * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus); - ASSERT (mSmmInterruptSspTables !=3D 0); - DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterru= ptSspTables)); - } - - // - // The highest address on the stack (0xFF8) is a save-previous-ssp t= oken pointing to a location that is 40 bytes away - 0xFD0. - // The supervisor shadow stack token is just above it at address 0xF= F0. This is where the interrupt SSP table points. - // So when an interrupt of exception occurs, we can use SAVESSP/REST= ORESSP/CLEARSSBUSY for the supervisor shadow stack, - // due to the reason the RETF in SMM exception handler cannot clear = the BUSY flag with same CPL. - // (only IRET or RETF with different CPL can clear BUSY flag) - // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for= the full stack frame at runtime. - // - InterruptSsp =3D (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) = - sizeof(UINT64)); - *(UINT64 *)(UINTN)InterruptSsp =3D (InterruptSsp - sizeof(UINT64) * = 4) | 0x2; - mCetInterruptSsp =3D InterruptSsp - sizeof(UINT64); - - mCetInterruptSspTable =3D (UINT32)(UINTN)(mSmmInterruptSspTables + s= izeof(UINT64) * 8 * CpuIndex); - InterruptSspTable =3D (UINT64 *)(UINTN)mCetInterruptSspTable; - InterruptSspTable[1] =3D mCetInterruptSsp; - PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4); - PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTab= le, 4); - DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp)); - DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptS= spTable)); + if (mSmmInterruptSspTables =3D=3D 0) { + mSmmInterruptSspTables =3D (UINTN)AllocateZeroPool(sizeof(UINT64) * = 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus); + ASSERT (mSmmInterruptSspTables !=3D 0); + DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterrupt= SspTables)); } + + // + // The highest address on the stack (0xFE0) is a save-previous-ssp tok= en pointing to a location that is 40 bytes away - 0xFB8. + // The supervisor shadow stack token is just above it at address 0xFD8= . This is where the interrupt SSP table points. + // So when an interrupt of exception occurs, we can use SAVESSP/RESTOR= ESSP/CLEARSSBUSY for the supervisor shadow stack, + // due to the reason the RETF in SMM exception handler cannot clear th= e BUSY flag with same CPL. + // (only IRET or RETF with different CPL can clear BUSY flag) + // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for t= he full stack frame at runtime. + // According to SDM (ver. 075 June 2021), shadow stack should be 32 by= tes aligned. + // + InterruptSsp =3D (UINT32)(((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) -= (sizeof(UINT64) * 4)) & ~0x1f); + *(UINT64 *)(UINTN)InterruptSsp =3D (InterruptSsp - sizeof(UINT64) * 4)= | 0x2; + mCetInterruptSsp =3D InterruptSsp - sizeof(UINT64); + + mCetInterruptSspTable =3D (UINT32)(UINTN)(mSmmInterruptSspTables + siz= eof(UINT64) * 8 * CpuIndex); + InterruptSspTable =3D (UINT64 *)(UINTN)mCetInterruptSspTable; + InterruptSspTable[1] =3D mCetInterruptSsp; + PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4); + PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable= , 4); + DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp)); + DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSsp= Table)); } } =20 --=20 2.16.2.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#83540): https://edk2.groups.io/g/devel/message/83540 Mute This Topic: https://groups.io/mt/86951557/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-