From db69014ad8703f949104311326f0ced9d33007ca Mon Sep 17 00:00:00 2001
From: Mikhail Krichanov <mikhailkrichanov@gmail.com>
Date: Tue, 9 Jan 2024 14:20:48 +0300
Subject: [PATCH] Ring3: Enabled SMAP and SMEP.

---
 .../Core/DxeIplPeim/X64/VirtualMemory.c       | 20 +++++++++++
 MdePkg/Include/Library/BaseLib.h              | 18 ++++++++++
 MdePkg/Library/BaseLib/BaseLib.inf            |  1 +
 MdePkg/Library/BaseLib/X64/WriteEflags.nasm   | 33 +++++++++++++++++++
 4 files changed, 72 insertions(+)
 create mode 100644 MdePkg/Library/BaseLib/X64/WriteEflags.nasm

diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index df6196a41c..b0b814a780 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -701,6 +701,10 @@ CreateIdentityMappingPageTables (
   PAGE_TABLE_1G_ENTRY                          *PageDirectory1GEntry;
   UINT64                                       AddressEncMask;
   IA32_CR4                                     Cr4;
+  IA32_EFLAGS32                                Eflags;
+  UINT32                                       Ebx;
+
+  Ebx = 0;
 
   //
   // Set PageMapLevel5Entry to suppress incorrect compiler/analyzer warnings
@@ -970,5 +974,21 @@ CreateIdentityMappingPageTables (
     EnableExecuteDisableBit ();
   }
 
+  //
+  // Forbid supervisor-mode accesses to any user-mode pages.
+  // SMEP and SMAP must be supported.
+  //
+  AsmCpuidEx (0x07, 0x0, NULL, &Ebx, NULL, NULL);
+  if (((Ebx & BIT20) != 0) && ((Ebx & BIT7) != 0)) {
+    Cr4.UintN     = AsmReadCr4 ();
+    Cr4.Bits.SMAP = 1;
+    Cr4.Bits.SMEP = 1;
+    AsmWriteCr4 (Cr4.UintN);
+
+    Eflags.UintN   = AsmReadEflags ();
+    Eflags.Bits.AC = 0;
+    AsmWriteEflags (Eflags.UintN);
+  }
+
   return (UINTN)PageMap;
 }
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 95f805599d..0f4542e8ef 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -6502,6 +6502,24 @@ AsmReadCr4 (
   VOID
   );
 
+/**
+  Writes a value to the EFLAGS register.
+
+  Writes and returns a new value to the EFLAGS register. This function is
+  only available on IA-32 and x64. This writes a 32-bit value on IA-32 and
+  a 64-bit value on x64.
+
+  @param  EFLAGS The value to write to EFLAGS.
+
+  @return The value written to EFLAGS.
+
+**/
+UINTN
+EFIAPI
+AsmWriteEflags (
+  UINTN  Eflags
+  );
+
 /**
   Writes a value to Control Register 0 (CR0).
 
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 26e66a8d67..dff5ca56af 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -294,6 +294,7 @@
   X64/ReadCr2.nasm| MSFT
   X64/ReadCr0.nasm| MSFT
   X64/ReadEflags.nasm| MSFT
+  X64/WriteEflags.nasm
 
   X64/TdCall.nasm
   X64/TdVmcall.nasm
diff --git a/MdePkg/Library/BaseLib/X64/WriteEflags.nasm b/MdePkg/Library/BaseLib/X64/WriteEflags.nasm
new file mode 100644
index 0000000000..85866a9899
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/WriteEflags.nasm
@@ -0,0 +1,33 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2024, Mikhail Krichanov. All rights reserved.
+; SPDX-License-Identifier: BSD-3-Clause
+;
+; Module Name:
+;
+;   WriteEflags.Asm
+;
+; Abstract:
+;
+;   AsmWriteEflags function
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+    DEFAULT REL
+    SECTION .text
+
+;------------------------------------------------------------------------------
+; UINTN
+; EFIAPI
+; AsmWriteEflags (
+;   UINTN  Eflags
+;   );
+;------------------------------------------------------------------------------
+global ASM_PFX(AsmWriteEflags)
+ASM_PFX(AsmWriteEflags):
+    push    rcx
+    popfq
+    mov     rax, rcx
+    ret