public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
@ 2018-09-14  5:13 Jian J Wang
  2018-09-14  5:46 ` Wang, Jian J
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Jian J Wang @ 2018-09-14  5:13 UTC (permalink / raw)
  To: edk2-devel; +Cc: Star Zeng, Laszlo Ersek, Ard Biesheuvel, Ruiyu Ni, Jiewen Yao

BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116

Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
confuses developers because following two other PCDs also need NXE
to be set, but actually not.

    PcdDxeNxMemoryProtectionPolicy
    PcdImageProtectionPolicy

This patch solves this issue by adding logic to enable IA32_EFER.NXE
if any of those PCDs have anything enabled.

Due to the fact that NX memory type of stack (enabled by PcdSetNxForStack)
and image data section (enabled by PcdImageProtectionPolicy) are also
part of PcdDxeNxMemoryProtectionPolicy, this patch also add more checks
to warn (ASSERT) users any unreasonable setting combinations. For example,

    PcdSetNxForStack == FALSE &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0

In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
priority over PcdDxeNxMemoryProtectionPolicy.

Cc: Star Zeng <star.zeng@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
---
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
 MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
 MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++++++++++++++-
 MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 ++++++++++++++
 4 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index fd82657404..068e700074 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -117,6 +117,8 @@
 
 [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## SOMETIMES_CONSUMES
 
 [Depex]
   gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
index d28baa3615..9a97205ef8 100644
--- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -245,7 +245,7 @@ ToBuildPageTable (
     return TRUE;
   }
 
-  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) {
+  if (ToEnableExecuteDisableFeature ()) {
     return TRUE;
   }
 
@@ -436,7 +436,7 @@ HandOffToDxeCore (
     BuildPageTablesIa32Pae = ToBuildPageTable ();
     if (BuildPageTablesIa32Pae) {
       PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
-      if (IsExecuteDisableBitAvailable ()) {
+      if (ToEnableExecuteDisableFeature ()) {
         EnableExecuteDisableBit();
       }
     }
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index 496e219913..253fe84223 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -106,6 +106,56 @@ IsNullDetectionEnabled (
   return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);
 }
 
+/**
+  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
+
+  @retval TRUE    IA32_EFER.NXE should be enabled.
+  @retval FALSE   IA32_EFER.NXE should not be enabled.
+
+**/
+BOOLEAN
+ToEnableExecuteDisableFeature (
+  VOID
+  )
+{
+  if (!IsExecuteDisableBitAvailable ()) {
+    return FALSE;
+  }
+
+  //
+  // Normally stack is type of EfiBootServicesData. Disabling NX for stack
+  // but enabling NX for EfiBootServicesData doesn't make any sense.
+  //
+  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
+      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0) {
+    DEBUG ((DEBUG_ERROR,
+            "ERROR: NX for stack is disabled but NX for its memory type is enabled!\r\n"));
+    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
+             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0));
+  }
+
+  //
+  // Image data section could be type of EfiLoaderData, EfiBootServicesData
+  // or EfiRuntimeServicesData. Disabling NX for image data but enabling NX
+  // for any those memory types doesn't make any sense.
+  //
+  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
+      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0) {
+    DEBUG ((DEBUG_ERROR,
+            "ERROR: NX for image data is disabled but NX for its memory type(s) is enabled!\r\n"));
+    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
+              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0));
+  }
+
+  //
+  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
+  // Features controlled by Following PCDs need this feature to be enabled.
+  //
+  return (PcdGetBool (PcdSetNxForStack) ||
+          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
+          PcdGet32 (PcdImageProtectionPolicy) != 0);
+}
+
 /**
   Enable Execute Disable Bit.
 
@@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
   //
   EnablePageTableProtection ((UINTN)PageMap, TRUE);
 
-  if (PcdGetBool (PcdSetNxForStack)) {
+  //
+  // Set IA32_EFER.NXE if necessary.
+  //
+  if (ToEnableExecuteDisableFeature ()) {
     EnableExecuteDisableBit ();
   }
 
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
index 85457ff937..9f152e6531 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
@@ -179,6 +179,39 @@ typedef struct {
   UINTN           FreePages;
 } PAGE_TABLE_POOL;
 
+//
+// Bit field repsentations of some EFI_MEMORY_TYPE, for page table initialization.
+//
+#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    /* 0x10 */
+#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | /* 0x04 */\
+                                     (1 << EfiBootServicesData) | /* 0x10 */\
+                                     (1 << EfiRuntimeServicesData)/* 0x40 */\
+                                    )                             /* 0x54 */
+
+/**
+  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
+
+  @retval TRUE    IA32_EFER.NXE should be enabled.
+  @retval FALSE   IA32_EFER.NXE should not be enabled.
+
+**/
+BOOLEAN
+ToEnableExecuteDisableFeature (
+  VOID
+  );
+
+/**
+  The function will check if Execute Disable Bit is available.
+
+  @retval TRUE      Execute Disable Bit is available.
+  @retval FALSE     Execute Disable Bit is not available.
+
+**/
+BOOLEAN
+IsExecuteDisableBitAvailable (
+  VOID
+  );
+
 /**
   Enable Execute Disable Bit.
 
-- 
2.16.2.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-14  5:13 [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs Jian J Wang
@ 2018-09-14  5:46 ` Wang, Jian J
  2018-09-14  6:04 ` Ard Biesheuvel
  2018-09-14  9:50 ` Laszlo Ersek
  2 siblings, 0 replies; 14+ messages in thread
From: Wang, Jian J @ 2018-09-14  5:46 UTC (permalink / raw)
  To: edk2-devel, edk2-devel@lists.01.org
  Cc: Ni, Ruiyu, Yao, Jiewen, Laszlo Ersek, Zeng, Star

Tests:
a. try all related PCDs combinations and check the page table attributes
    and ASSERT message
b. boot to shell on real intel platform with valid PCD setting combinations (IA32/X64)
c. boot to fedora26, ubuntu18.04, windows 7 and windows 10 on OVMF  emulated
    platform (X64)

Regards,
Jian

> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org]
> Sent: Friday, September 14, 2018 1:14 PM
> To: edk2-devel@lists.01.org
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Laszlo Ersek <lersek@redhat.com>; Zeng, Star <star.zeng@intel.com>
> Subject: [edk2] [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
> 
> Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
> confuses developers because following two other PCDs also need NXE
> to be set, but actually not.
> 
>     PcdDxeNxMemoryProtectionPolicy
>     PcdImageProtectionPolicy
> 
> This patch solves this issue by adding logic to enable IA32_EFER.NXE
> if any of those PCDs have anything enabled.
> 
> Due to the fact that NX memory type of stack (enabled by PcdSetNxForStack)
> and image data section (enabled by PcdImageProtectionPolicy) are also
> part of PcdDxeNxMemoryProtectionPolicy, this patch also add more checks
> to warn (ASSERT) users any unreasonable setting combinations. For example,
> 
>     PcdSetNxForStack == FALSE &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
> 
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0
> 
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
> 
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
> 
> In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
> priority over PcdDxeNxMemoryProtectionPolicy.
> 
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> ---
>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
>  MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55
> +++++++++++++++++++++++-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 ++++++++++++++
>  4 files changed, 91 insertions(+), 3 deletions(-)
> 
> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> index fd82657404..068e700074 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> @@ -117,6 +117,8 @@
> 
>  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ##
> SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ##
> SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ##
> SOMETIMES_CONSUMES
> 
>  [Depex]
>    gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> index d28baa3615..9a97205ef8 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> @@ -245,7 +245,7 @@ ToBuildPageTable (
>      return TRUE;
>    }
> 
> -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) {
> +  if (ToEnableExecuteDisableFeature ()) {
>      return TRUE;
>    }
> 
> @@ -436,7 +436,7 @@ HandOffToDxeCore (
>      BuildPageTablesIa32Pae = ToBuildPageTable ();
>      if (BuildPageTablesIa32Pae) {
>        PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
> -      if (IsExecuteDisableBitAvailable ()) {
> +      if (ToEnableExecuteDisableFeature ()) {
>          EnableExecuteDisableBit();
>        }
>      }
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> index 496e219913..253fe84223 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
>    return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);
>  }
> 
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  )
> +{
> +  if (!IsExecuteDisableBitAvailable ()) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Normally stack is type of EfiBootServicesData. Disabling NX for stack
> +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> +  //
> +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> STACK_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for stack is disabled but NX for its memory type is
> enabled!\r\n"));
> +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> STACK_MEMORY_TYPE) != 0));
> +  }
> +
> +  //
> +  // Image data section could be type of EfiLoaderData, EfiBootServicesData
> +  // or EfiRuntimeServicesData. Disabling NX for image data but enabling NX
> +  // for any those memory types doesn't make any sense.
> +  //
> +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> IMAGE_DATA_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for image data is disabled but NX for its memory type(s) is
> enabled!\r\n"));
> +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> IMAGE_DATA_MEMORY_TYPE) != 0));
> +  }
> +
> +  //
> +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> +  // Features controlled by Following PCDs need this feature to be enabled.
> +  //
> +  return (PcdGetBool (PcdSetNxForStack) ||
> +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> +}
> +
>  /**
>    Enable Execute Disable Bit.
> 
> @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
>    //
>    EnablePageTableProtection ((UINTN)PageMap, TRUE);
> 
> -  if (PcdGetBool (PcdSetNxForStack)) {
> +  //
> +  // Set IA32_EFER.NXE if necessary.
> +  //
> +  if (ToEnableExecuteDisableFeature ()) {
>      EnableExecuteDisableBit ();
>    }
> 
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> index 85457ff937..9f152e6531 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> @@ -179,6 +179,39 @@ typedef struct {
>    UINTN           FreePages;
>  } PAGE_TABLE_POOL;
> 
> +//
> +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table
> initialization.
> +//
> +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    /* 0x10 */
> +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | /* 0x04
> */\
> +                                     (1 << EfiBootServicesData) | /* 0x10 */\
> +                                     (1 << EfiRuntimeServicesData)/* 0x40 */\
> +                                    )                             /* 0x54 */
> +
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  );
> +
> +/**
> +  The function will check if Execute Disable Bit is available.
> +
> +  @retval TRUE      Execute Disable Bit is available.
> +  @retval FALSE     Execute Disable Bit is not available.
> +
> +**/
> +BOOLEAN
> +IsExecuteDisableBitAvailable (
> +  VOID
> +  );
> +
>  /**
>    Enable Execute Disable Bit.
> 
> --
> 2.16.2.windows.1
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-14  5:13 [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs Jian J Wang
  2018-09-14  5:46 ` Wang, Jian J
@ 2018-09-14  6:04 ` Ard Biesheuvel
  2018-09-14  6:50   ` Wang, Jian J
  2018-09-14  9:50 ` Laszlo Ersek
  2 siblings, 1 reply; 14+ messages in thread
From: Ard Biesheuvel @ 2018-09-14  6:04 UTC (permalink / raw)
  To: Jian J Wang
  Cc: edk2-devel@lists.01.org, Star Zeng, Laszlo Ersek, Ruiyu Ni,
	Jiewen Yao

On 14 September 2018 at 07:13, Jian J Wang <jian.j.wang@intel.com> wrote:
> BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
>
> Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
> confuses developers because following two other PCDs also need NXE
> to be set, but actually not.
>
>     PcdDxeNxMemoryProtectionPolicy
>     PcdImageProtectionPolicy
>
> This patch solves this issue by adding logic to enable IA32_EFER.NXE
> if any of those PCDs have anything enabled.
>
> Due to the fact that NX memory type of stack (enabled by PcdSetNxForStack)
> and image data section (enabled by PcdImageProtectionPolicy) are also
> part of PcdDxeNxMemoryProtectionPolicy, this patch also add more checks
> to warn (ASSERT) users any unreasonable setting combinations. For example,
>
>     PcdSetNxForStack == FALSE &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
>
> In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
> priority over PcdDxeNxMemoryProtectionPolicy.
>

Why? Is it unreasonable to protect the stack but not other
EfiBootServicesData regions?

I am trying to understand if you think these are fundamentally
incompatible, or whether it is simply too complicated in the code to
support it. (I can see how the first example would force you to
explicitly map the stack executable, for instance, which is perhaps a
bit of a stretch)

> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> ---
>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
>  MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++++++++++++++-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 ++++++++++++++
>  4 files changed, 91 insertions(+), 3 deletions(-)
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> index fd82657404..068e700074 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> @@ -117,6 +117,8 @@
>
>  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## SOMETIMES_CONSUMES
>
>  [Depex]
>    gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> index d28baa3615..9a97205ef8 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> @@ -245,7 +245,7 @@ ToBuildPageTable (
>      return TRUE;
>    }
>
> -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) {
> +  if (ToEnableExecuteDisableFeature ()) {
>      return TRUE;
>    }
>
> @@ -436,7 +436,7 @@ HandOffToDxeCore (
>      BuildPageTablesIa32Pae = ToBuildPageTable ();
>      if (BuildPageTablesIa32Pae) {
>        PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
> -      if (IsExecuteDisableBitAvailable ()) {
> +      if (ToEnableExecuteDisableFeature ()) {
>          EnableExecuteDisableBit();
>        }
>      }
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> index 496e219913..253fe84223 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
>    return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);
>  }
>
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  )
> +{
> +  if (!IsExecuteDisableBitAvailable ()) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Normally stack is type of EfiBootServicesData. Disabling NX for stack
> +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> +  //
> +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for stack is disabled but NX for its memory type is enabled!\r\n"));
> +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0));
> +  }
> +
> +  //
> +  // Image data section could be type of EfiLoaderData, EfiBootServicesData
> +  // or EfiRuntimeServicesData. Disabling NX for image data but enabling NX
> +  // for any those memory types doesn't make any sense.
> +  //
> +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for image data is disabled but NX for its memory type(s) is enabled!\r\n"));
> +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0));
> +  }
> +
> +  //
> +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> +  // Features controlled by Following PCDs need this feature to be enabled.
> +  //
> +  return (PcdGetBool (PcdSetNxForStack) ||
> +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> +}
> +
>  /**
>    Enable Execute Disable Bit.
>
> @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
>    //
>    EnablePageTableProtection ((UINTN)PageMap, TRUE);
>
> -  if (PcdGetBool (PcdSetNxForStack)) {
> +  //
> +  // Set IA32_EFER.NXE if necessary.
> +  //
> +  if (ToEnableExecuteDisableFeature ()) {
>      EnableExecuteDisableBit ();
>    }
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> index 85457ff937..9f152e6531 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> @@ -179,6 +179,39 @@ typedef struct {
>    UINTN           FreePages;
>  } PAGE_TABLE_POOL;
>
> +//
> +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table initialization.
> +//
> +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    /* 0x10 */
> +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | /* 0x04 */\
> +                                     (1 << EfiBootServicesData) | /* 0x10 */\
> +                                     (1 << EfiRuntimeServicesData)/* 0x40 */\
> +                                    )                             /* 0x54 */
> +
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  );
> +
> +/**
> +  The function will check if Execute Disable Bit is available.
> +
> +  @retval TRUE      Execute Disable Bit is available.
> +  @retval FALSE     Execute Disable Bit is not available.
> +
> +**/
> +BOOLEAN
> +IsExecuteDisableBitAvailable (
> +  VOID
> +  );
> +
>  /**
>    Enable Execute Disable Bit.
>
> --
> 2.16.2.windows.1
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-14  6:04 ` Ard Biesheuvel
@ 2018-09-14  6:50   ` Wang, Jian J
  2018-09-14  9:27     ` Laszlo Ersek
  0 siblings, 1 reply; 14+ messages in thread
From: Wang, Jian J @ 2018-09-14  6:50 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: edk2-devel@lists.01.org, Zeng, Star, Laszlo Ersek, Ni, Ruiyu,
	Yao, Jiewen

Ard,

> Why? Is it unreasonable to protect the stack but not other
> EfiBootServicesData regions?

I think you got me wrong. It's reasonable to protect stack but not
other EfiBootServicesData regions. What I want to express in the
commit message is the contrary one is not: not to protect stack but
protect all EfiBootServicesData regions. I have one statement at
the end of message saying "PcdSetNxForStack and PcdImageProtectionPolicy
have priority over PcdDxeNxMemoryProtectionPolicy". Do you agree
with it?

The examples I gave are unreasonable ones. I can't image any
reason to try those combinations on purpose. But if there's really
good reason to do it, it's ok to remove those checks.

> I am trying to understand if you think these are fundamentally
> incompatible, or whether it is simply too complicated in the code to
> support it. (I can see how the first example would force you to
>  explicitly map the stack executable, for instance, which is perhaps a
> bit of a stretch)

I might not get your point here. If I understand correctly, I think the
purpose I want to do here is to avoid any unexpected NX behavior from BIOS.
For example, if one don't want NX for stack and set PcdSetNxForStack to
FALSE but accidently enabled NX for EfiBootServicesData, it's hard for him
to find out why stack is still not executable. This usually happen if one is trying
different configurations to debug the system.

Or do you mean if one set PcdSetNxForStack to FALSE, the BIOS should
automatically disable NX for all EfiBootServicesData regions? This is a bit
confuse to me because, if PcdSetNxForStack is TRUE, we only enable NX
for stack memory only (suppose PcdDxeNxMemoryProtectionPolicy is all zero).

Regards,
Jian

From: Ard Biesheuvel [mailto:ard.biesheuvel@linaro.org] 
Sent: Friday, September 14, 2018 2:05 PM
To: Wang, Jian J <jian.j.wang@intel.com>
Cc: edk2-devel@lists.01.org; Zeng, Star <star.zeng@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs

On 14 September 2018 at 07:13, Jian J Wang <jian.j.wang@intel.com> wrote:
> BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
>
> Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
> confuses developers because following two other PCDs also need NXE
> to be set, but actually not.
>
>     PcdDxeNxMemoryProtectionPolicy
>     PcdImageProtectionPolicy
>
> This patch solves this issue by adding logic to enable IA32_EFER.NXE
> if any of those PCDs have anything enabled.
>
> Due to the fact that NX memory type of stack (enabled by PcdSetNxForStack)
> and image data section (enabled by PcdImageProtectionPolicy) are also
> part of PcdDxeNxMemoryProtectionPolicy, this patch also add more checks
> to warn (ASSERT) users any unreasonable setting combinations. For example,
>
>     PcdSetNxForStack == FALSE &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
>
> In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
> priority over PcdDxeNxMemoryProtectionPolicy.
>

Why? Is it unreasonable to protect the stack but not other
EfiBootServicesData regions?

I am trying to understand if you think these are fundamentally
incompatible, or whether it is simply too complicated in the code to
support it. (I can see how the first example would force you to
explicitly map the stack executable, for instance, which is perhaps a
bit of a stretch)

> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> ---
>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
>  MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++++++++++++++-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 ++++++++++++++
>  4 files changed, 91 insertions(+), 3 deletions(-)
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> index fd82657404..068e700074 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> @@ -117,6 +117,8 @@
>
>  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## SOMETIMES_CONSUMES
>
>  [Depex]
>    gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> index d28baa3615..9a97205ef8 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> @@ -245,7 +245,7 @@ ToBuildPageTable (
>      return TRUE;
>    }
>
> -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) {
> +  if (ToEnableExecuteDisableFeature ()) {
>      return TRUE;
>    }
>
> @@ -436,7 +436,7 @@ HandOffToDxeCore (
>      BuildPageTablesIa32Pae = ToBuildPageTable ();
>      if (BuildPageTablesIa32Pae) {
>        PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
> -      if (IsExecuteDisableBitAvailable ()) {
> +      if (ToEnableExecuteDisableFeature ()) {
>          EnableExecuteDisableBit();
>        }
>      }
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> index 496e219913..253fe84223 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
>    return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);
>  }
>
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  )
> +{
> +  if (!IsExecuteDisableBitAvailable ()) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Normally stack is type of EfiBootServicesData. Disabling NX for stack
> +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> +  //
> +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for stack is disabled but NX for its memory type is enabled!\r\n"));
> +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0));
> +  }
> +
> +  //
> +  // Image data section could be type of EfiLoaderData, EfiBootServicesData
> +  // or EfiRuntimeServicesData. Disabling NX for image data but enabling NX
> +  // for any those memory types doesn't make any sense.
> +  //
> +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for image data is disabled but NX for its memory type(s) is enabled!\r\n"));
> +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0));
> +  }
> +
> +  //
> +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> +  // Features controlled by Following PCDs need this feature to be enabled.
> +  //
> +  return (PcdGetBool (PcdSetNxForStack) ||
> +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> +}
> +
>  /**
>    Enable Execute Disable Bit.
>
> @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
>    //
>    EnablePageTableProtection ((UINTN)PageMap, TRUE);
>
> -  if (PcdGetBool (PcdSetNxForStack)) {
> +  //
> +  // Set IA32_EFER.NXE if necessary.
> +  //
> +  if (ToEnableExecuteDisableFeature ()) {
>      EnableExecuteDisableBit ();
>    }
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> index 85457ff937..9f152e6531 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> @@ -179,6 +179,39 @@ typedef struct {
>    UINTN           FreePages;
>  } PAGE_TABLE_POOL;
>
> +//
> +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table initialization.
> +//
> +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    /* 0x10 */
> +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | /* 0x04 */\
> +                                     (1 << EfiBootServicesData) | /* 0x10 */\
> +                                     (1 << EfiRuntimeServicesData)/* 0x40 */\
> +                                    )                             /* 0x54 */
> +
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  );
> +
> +/**
> +  The function will check if Execute Disable Bit is available.
> +
> +  @retval TRUE      Execute Disable Bit is available.
> +  @retval FALSE     Execute Disable Bit is not available.
> +
> +**/
> +BOOLEAN
> +IsExecuteDisableBitAvailable (
> +  VOID
> +  );
> +
>  /**
>    Enable Execute Disable Bit.
>
> --
> 2.16.2.windows.1
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-14  6:50   ` Wang, Jian J
@ 2018-09-14  9:27     ` Laszlo Ersek
  2018-09-17  1:00       ` Wang, Jian J
  0 siblings, 1 reply; 14+ messages in thread
From: Laszlo Ersek @ 2018-09-14  9:27 UTC (permalink / raw)
  To: Wang, Jian J, Ard Biesheuvel
  Cc: edk2-devel@lists.01.org, Zeng, Star, Ni, Ruiyu, Yao, Jiewen

On 09/14/18 08:50, Wang, Jian J wrote:
> Ard,
>
>> Why? Is it unreasonable to protect the stack but not other
>> EfiBootServicesData regions?
>
> I think you got me wrong. It's reasonable to protect stack but not
> other EfiBootServicesData regions. What I want to express in the
> commit message is the contrary one is not: not to protect stack but
> protect all EfiBootServicesData regions. I have one statement at the
> end of message saying "PcdSetNxForStack and PcdImageProtectionPolicy
> have priority over PcdDxeNxMemoryProtectionPolicy". Do you agree with
> it?
>
> The examples I gave are unreasonable ones. I can't image any
> reason to try those combinations on purpose. But if there's really
> good reason to do it, it's ok to remove those checks.

The issue is with the wording. "Taking priority" means "resolving an
inconsistency by force". That is, we have two settings that contradict
each other, but one of those settings is considered stronger, and the
other weaker. Thus the former takes priority, and the latter is ignored.

But that's not what we're doing here. We're ensuring that there is no
inconsistency in the first place. If there is, we catch it with an
assert. Therefore there is no priority ordering between the settings,
they are equally strong, and they must not be in disagreement.

(PcdSetNxForStack being set, and PcdDxeNxMemoryProtectionPolicy being
clear, are *not* inconsistent; so there is no need to give priority to
one over the other.)

The word that we are looking for is "implies". In logic, if we have a
formula

  A --> B

we read it as "A implies B". The expression is true if "A" is false
(everything follows from false, or put differently, false implies
everything), or else, if "A" is true, then "B" must be true as well.
Otherwise the expression evaluates to true.

In the C language, we don't have an "imply" operator. Luckily, the same
predicate (the implication) can be written with the logical negation and
"or" operators, like this:

  !A || B

It is exactly the same thing. If "A" is false, then the expression is
true (regardless of the value of "B"). If "A" is true, then the
expression is only true if "B" is true as well (that is, if "A" in fact
implies "B").


So, back to the concrete topic. The original predicate we want to ensure
is the following [1]:

  ((DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack) AND
  ((DxeNxMemoryProtectionPolicy covers RSD) --> ImageProtectionPolicy) AND
  ((DxeNxMemoryProtectionPolicy covers BSD) --> ImageProtectionPolicy) AND
  ((DxeNxMemoryProtectionPolicy covers LD) --> ImageProtectionPolicy)

In English language, this reads:

- if DxeNxMemoryProtectionPolicy covers BootServicesData, then
  SetNxForStack must be true (the former "implies" the latter), AND

- if DxeNxMemoryProtectionPolicy covers RuntimeServicesData, then
  PcdImageProtectionPolicy must be nonzero (the former "implies" the
  latter), AND

- ... so on and so forth.

(We are past *why* we want to ensure these, I think, but I can repeat
it, for the first one anyway: the stack is mostly located in boot
services data type memory, and marking all that memory NX via
DxeNxMemoryProtectionPolicy, while *not* marking the stack subset of it
via SetNxForStack, would be counter-intuitive / self-contradictory.

When both of those settings are "on", that's fine.

It's also fine when *only* SetNxForStack is "on".

This means that the statement "DxeNxMemoryProtectionPolicy covers BSD"
*implies* (or "requires") that SetNxForStack is "on".)


Now, in order to eliminate the "implies" operator, we can transcribe the
predicate as follows, using the equivalence I mentioned at the top
(i.e., (A --> B) === (!A || B)):

  (NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack) AND
  (NOT(DxeNxMemoryProtectionPolicy covers RSD) OR ImageProtectionPolicy) AND
  (NOT(DxeNxMemoryProtectionPolicy covers BSD) OR ImageProtectionPolicy) AND
  (NOT(DxeNxMemoryProtectionPolicy covers LD) OR ImageProtectionPolicy)

Finally, in order to calculate the condition for triggering the
*failure* case, we have to negate the above predicate. It starts with
slapping a huge NOT() around the whole predicate, of course; but we can
do better, by pushing down NOT(). And for that, we use De Morgan's Laws,
that is:

  !(A || B) === !A && !B
  !(A && B) === !A || !B

which, after repeated application, gives us for the failure condition:

  ((DxeNxMemoryProtectionPolicy covers BSD) AND NOT(SetNxForStack)) OR
  ((DxeNxMemoryProtectionPolicy covers RSD) AND NOT(ImageProtectionPolicy)) OR
  ((DxeNxMemoryProtectionPolicy covers BSD) AND NOT(ImageProtectionPolicy)) OR
  ((DxeNxMemoryProtectionPolicy covers LD) AND NOT(ImageProtectionPolicy))

This is exactly what Jian wrote in the commit message (not accounting
for the short-circuit behavior of the && operator -- but in this case,
short-circuiting doesn't matter, because there are no side effects to
the sub-expressions):

    PcdSetNxForStack == FALSE &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0

I believe we agree on the desired condition, it's just that the commit
message should not say

> PcdSetNxForStack and PcdImageProtectionPolicy have priority over
> PcdDxeNxMemoryProtectionPolicy

instead it should cite our consistency requirement (see [1] above).

--*--

Actually, I do have a suggestion for improving the C-language condition
further (the logical predicate is fine as-is). I suggest replacing

  PcdImageProtectionPolicy == 0

with

  PcdImageProtectionPolicy != 3

Because, PcdDxeNxMemoryProtectionPolicy will mark the data section
non-executable *regardless* of where any given image comes from (unknown
device or firmware volume). Therefore, if PcdDxeNxMemoryProtectionPolicy
is "on" (for RSD / BSD / LD), then the platform must explicitly request
image protection for images from *both* origins.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-14  5:13 [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs Jian J Wang
  2018-09-14  5:46 ` Wang, Jian J
  2018-09-14  6:04 ` Ard Biesheuvel
@ 2018-09-14  9:50 ` Laszlo Ersek
  2018-09-17  2:11   ` Wang, Jian J
  2 siblings, 1 reply; 14+ messages in thread
From: Laszlo Ersek @ 2018-09-14  9:50 UTC (permalink / raw)
  To: Jian J Wang, edk2-devel; +Cc: Star Zeng, Ard Biesheuvel, Ruiyu Ni, Jiewen Yao

I've got some comments on the code as well:

On 09/14/18 07:13, Jian J Wang wrote:
> BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
>
> Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
> confuses developers because following two other PCDs also need NXE
> to be set, but actually not.
>
>     PcdDxeNxMemoryProtectionPolicy
>     PcdImageProtectionPolicy
>
> This patch solves this issue by adding logic to enable IA32_EFER.NXE
> if any of those PCDs have anything enabled.
>
> Due to the fact that NX memory type of stack (enabled by PcdSetNxForStack)
> and image data section (enabled by PcdImageProtectionPolicy) are also
> part of PcdDxeNxMemoryProtectionPolicy, this patch also add more checks
> to warn (ASSERT) users any unreasonable setting combinations. For example,
>
>     PcdSetNxForStack == FALSE &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
>
>     PcdImageProtectionPolicy == 0 &&
>       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
>
> In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
> priority over PcdDxeNxMemoryProtectionPolicy.
>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> ---
>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
>  MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++++++++++++++-
>  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 ++++++++++++++
>  4 files changed, 91 insertions(+), 3 deletions(-)
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> index fd82657404..068e700074 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> @@ -117,6 +117,8 @@
>
>  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## SOMETIMES_CONSUMES
>
>  [Depex]
>    gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> index d28baa3615..9a97205ef8 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> @@ -245,7 +245,7 @@ ToBuildPageTable (
>      return TRUE;
>    }
>
> -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) {
> +  if (ToEnableExecuteDisableFeature ()) {
>      return TRUE;
>    }
>
> @@ -436,7 +436,7 @@ HandOffToDxeCore (
>      BuildPageTablesIa32Pae = ToBuildPageTable ();
>      if (BuildPageTablesIa32Pae) {
>        PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
> -      if (IsExecuteDisableBitAvailable ()) {
> +      if (ToEnableExecuteDisableFeature ()) {
>          EnableExecuteDisableBit();
>        }
>      }
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> index 496e219913..253fe84223 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
>    return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);
>  }
>
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  )

I think we're over-complicating the name of this function. First, "To"
looks unnecessary. Second, "Enable Execute Disable" is just an
engineer's way to say "Disable Execution". Can we say right that:
DisableExec()?

Or at least, if we consider "NX" a word in its own right, "EnableNX()"?

> +{
> +  if (!IsExecuteDisableBitAvailable ()) {
> +    return FALSE;
> +  }
> +
> +  //
> +  // Normally stack is type of EfiBootServicesData. Disabling NX for stack
> +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> +  //

This comment is good.

> +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&

Please don't compare PcdGetBool() against TRUE or FALSE, just say
PcdGetBool(), or !PcdGetBool().

> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for stack is disabled but NX for its memory type is enabled!\r\n"));
> +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) != 0));
> +  }

Please drop both the explicit "if", and the DEBUG message. Just keep the
comment (which is already fine) and the ASSERT(). The ASSERT() will tell
people where to look, and the comment will explain the assertion. Also,
in a RELEASE build, the check should be eliminated entirely, but that
might not work for the explicit "if" (dependent on compilers and/or
fixed vs. dynamic PCDs).

Furthermore, keeping the logical negation operator as the outermost
operator makes the code a lot harder to read. It's much better to just
assert what we actually require, which is:

  (DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack

put differently,

  NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack

in C:

  ASSERT (
    (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) == 0 ||
    PcdGetBool (PcdSetNxForStack)
    );

> +
> +  //
> +  // Image data section could be type of EfiLoaderData, EfiBootServicesData
> +  // or EfiRuntimeServicesData. Disabling NX for image data but enabling NX
> +  // for any those memory types doesn't make any sense.
> +  //

The comment is good, I just suggest extending it with the origin of the
image: "Disabling NX for image data (regardless of image origin) for any
those memory types ...".

> +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0) {
> +    DEBUG ((DEBUG_ERROR,
> +            "ERROR: NX for image data is disabled but NX for its memory type(s) is enabled!\r\n"));
> +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) != 0));
> +  }

Summarizing my points from before, here we should have:

  ASSERT (
    (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TYPE) == 0 ||
    PcdGet32 (PcdImageProtectionPolicy) == 3
    );

That is,

- If we disable DxeNxMemoryProtectionPolicy for all of EfiLoaderData,
  EfiBootServicesData, and EfiRuntimeServicesData, then any
  ImageProtectionPolicy is fine.

- If we enable  DxeNxMemoryProtectionPolicy for any of EfiLoaderData,
  EfiBootServicesData, and EfiRuntimeServicesData, then we require the
  platform to set ImageProtectionPolicy regardless of image origin.

Thanks
Laszlo

> +
> +  //
> +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> +  // Features controlled by Following PCDs need this feature to be enabled.
> +  //
> +  return (PcdGetBool (PcdSetNxForStack) ||
> +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> +}
> +
>  /**
>    Enable Execute Disable Bit.
>
> @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
>    //
>    EnablePageTableProtection ((UINTN)PageMap, TRUE);
>
> -  if (PcdGetBool (PcdSetNxForStack)) {
> +  //
> +  // Set IA32_EFER.NXE if necessary.
> +  //
> +  if (ToEnableExecuteDisableFeature ()) {
>      EnableExecuteDisableBit ();
>    }
>
> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> index 85457ff937..9f152e6531 100644
> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> @@ -179,6 +179,39 @@ typedef struct {
>    UINTN           FreePages;
>  } PAGE_TABLE_POOL;
>
> +//
> +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table initialization.
> +//
> +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    /* 0x10 */
> +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | /* 0x04 */\
> +                                     (1 << EfiBootServicesData) | /* 0x10 */\
> +                                     (1 << EfiRuntimeServicesData)/* 0x40 */\
> +                                    )                             /* 0x54 */
> +
> +/**
> +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> +
> +  @retval TRUE    IA32_EFER.NXE should be enabled.
> +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> +
> +**/
> +BOOLEAN
> +ToEnableExecuteDisableFeature (
> +  VOID
> +  );
> +
> +/**
> +  The function will check if Execute Disable Bit is available.
> +
> +  @retval TRUE      Execute Disable Bit is available.
> +  @retval FALSE     Execute Disable Bit is not available.
> +
> +**/
> +BOOLEAN
> +IsExecuteDisableBitAvailable (
> +  VOID
> +  );
> +
>  /**
>    Enable Execute Disable Bit.
>
>



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-14  9:27     ` Laszlo Ersek
@ 2018-09-17  1:00       ` Wang, Jian J
  0 siblings, 0 replies; 14+ messages in thread
From: Wang, Jian J @ 2018-09-17  1:00 UTC (permalink / raw)
  To: Laszlo Ersek, Ard Biesheuvel
  Cc: edk2-devel@lists.01.org, Zeng, Star, Ni, Ruiyu, Yao, Jiewen

Laszlo,

Thank you very much for the explanations. I learned a lot from them.
I’ll update the patch just as what you suggested.

Regards,
Jian

From: Laszlo Ersek [mailto:lersek@redhat.com]
Sent: Friday, September 14, 2018 5:27 PM
To: Wang, Jian J <jian.j.wang@intel.com>; Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: edk2-devel@lists.01.org; Zeng, Star <star.zeng@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs

On 09/14/18 08:50, Wang, Jian J wrote:
> Ard,
>
>> Why? Is it unreasonable to protect the stack but not other
>> EfiBootServicesData regions?
>
> I think you got me wrong. It's reasonable to protect stack but not
> other EfiBootServicesData regions. What I want to express in the
> commit message is the contrary one is not: not to protect stack but
> protect all EfiBootServicesData regions. I have one statement at the
> end of message saying "PcdSetNxForStack and PcdImageProtectionPolicy
> have priority over PcdDxeNxMemoryProtectionPolicy". Do you agree with
> it?
>
> The examples I gave are unreasonable ones. I can't image any
> reason to try those combinations on purpose. But if there's really
> good reason to do it, it's ok to remove those checks.

The issue is with the wording. "Taking priority" means "resolving an
inconsistency by force". That is, we have two settings that contradict
each other, but one of those settings is considered stronger, and the
other weaker. Thus the former takes priority, and the latter is ignored.

But that's not what we're doing here. We're ensuring that there is no
inconsistency in the first place. If there is, we catch it with an
assert. Therefore there is no priority ordering between the settings,
they are equally strong, and they must not be in disagreement.

(PcdSetNxForStack being set, and PcdDxeNxMemoryProtectionPolicy being
clear, are *not* inconsistent; so there is no need to give priority to
one over the other.)

The word that we are looking for is "implies". In logic, if we have a
formula

  A --> B

we read it as "A implies B". The expression is true if "A" is false
(everything follows from false, or put differently, false implies
everything), or else, if "A" is true, then "B" must be true as well.
Otherwise the expression evaluates to true.

In the C language, we don't have an "imply" operator. Luckily, the same
predicate (the implication) can be written with the logical negation and
"or" operators, like this:

  !A || B

It is exactly the same thing. If "A" is false, then the expression is
true (regardless of the value of "B"). If "A" is true, then the
expression is only true if "B" is true as well (that is, if "A" in fact
implies "B").


So, back to the concrete topic. The original predicate we want to ensure
is the following [1]:

  ((DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack) AND
  ((DxeNxMemoryProtectionPolicy covers RSD) --> ImageProtectionPolicy) AND
  ((DxeNxMemoryProtectionPolicy covers BSD) --> ImageProtectionPolicy) AND
  ((DxeNxMemoryProtectionPolicy covers LD) --> ImageProtectionPolicy)

In English language, this reads:

- if DxeNxMemoryProtectionPolicy covers BootServicesData, then
  SetNxForStack must be true (the former "implies" the latter), AND

- if DxeNxMemoryProtectionPolicy covers RuntimeServicesData, then
  PcdImageProtectionPolicy must be nonzero (the former "implies" the
  latter), AND

- ... so on and so forth.

(We are past *why* we want to ensure these, I think, but I can repeat
it, for the first one anyway: the stack is mostly located in boot
services data type memory, and marking all that memory NX via
DxeNxMemoryProtectionPolicy, while *not* marking the stack subset of it
via SetNxForStack, would be counter-intuitive / self-contradictory.

When both of those settings are "on", that's fine.

It's also fine when *only* SetNxForStack is "on".

This means that the statement "DxeNxMemoryProtectionPolicy covers BSD"
*implies* (or "requires") that SetNxForStack is "on".)


Now, in order to eliminate the "implies" operator, we can transcribe the
predicate as follows, using the equivalence I mentioned at the top
(i.e., (A --> B) === (!A || B)):

  (NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack) AND
  (NOT(DxeNxMemoryProtectionPolicy covers RSD) OR ImageProtectionPolicy) AND
  (NOT(DxeNxMemoryProtectionPolicy covers BSD) OR ImageProtectionPolicy) AND
  (NOT(DxeNxMemoryProtectionPolicy covers LD) OR ImageProtectionPolicy)

Finally, in order to calculate the condition for triggering the
*failure* case, we have to negate the above predicate. It starts with
slapping a huge NOT() around the whole predicate, of course; but we can
do better, by pushing down NOT(). And for that, we use De Morgan's Laws,
that is:

  !(A || B) === !A && !B
  !(A && B) === !A || !B

which, after repeated application, gives us for the failure condition:

  ((DxeNxMemoryProtectionPolicy covers BSD) AND NOT(SetNxForStack)) OR
  ((DxeNxMemoryProtectionPolicy covers RSD) AND NOT(ImageProtectionPolicy)) OR
  ((DxeNxMemoryProtectionPolicy covers BSD) AND NOT(ImageProtectionPolicy)) OR
  ((DxeNxMemoryProtectionPolicy covers LD) AND NOT(ImageProtectionPolicy))

This is exactly what Jian wrote in the commit message (not accounting
for the short-circuit behavior of the && operator -- but in this case,
short-circuiting doesn't matter, because there are no side effects to
the sub-expressions):

    PcdSetNxForStack == FALSE &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0

    PcdImageProtectionPolicy == 0 &&
      (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0

I believe we agree on the desired condition, it's just that the commit
message should not say

> PcdSetNxForStack and PcdImageProtectionPolicy have priority over
> PcdDxeNxMemoryProtectionPolicy

instead it should cite our consistency requirement (see [1] above).

--*--

Actually, I do have a suggestion for improving the C-language condition
further (the logical predicate is fine as-is). I suggest replacing

  PcdImageProtectionPolicy == 0

with

  PcdImageProtectionPolicy != 3

Because, PcdDxeNxMemoryProtectionPolicy will mark the data section
non-executable *regardless* of where any given image comes from (unknown
device or firmware volume). Therefore, if PcdDxeNxMemoryProtectionPolicy
is "on" (for RSD / BSD / LD), then the platform must explicitly request
image protection for images from *both* origins.

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-14  9:50 ` Laszlo Ersek
@ 2018-09-17  2:11   ` Wang, Jian J
  2018-09-17  5:57     ` Zeng, Star
  0 siblings, 1 reply; 14+ messages in thread
From: Wang, Jian J @ 2018-09-17  2:11 UTC (permalink / raw)
  To: Laszlo Ersek, edk2-devel@lists.01.org
  Cc: Zeng, Star, Ard Biesheuvel, Ni, Ruiyu, Yao, Jiewen

Laszlo,

Thanks for the comments.

Regards,
Jian

> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Friday, September 14, 2018 5:51 PM
> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel
> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen
> <jiewen.yao@intel.com>
> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> I've got some comments on the code as well:
> 
> On 09/14/18 07:13, Jian J Wang wrote:
> > BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
> >
> > Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
> > confuses developers because following two other PCDs also need NXE
> > to be set, but actually not.
> >
> >     PcdDxeNxMemoryProtectionPolicy
> >     PcdImageProtectionPolicy
> >
> > This patch solves this issue by adding logic to enable IA32_EFER.NXE
> > if any of those PCDs have anything enabled.
> >
> > Due to the fact that NX memory type of stack (enabled by PcdSetNxForStack)
> > and image data section (enabled by PcdImageProtectionPolicy) are also
> > part of PcdDxeNxMemoryProtectionPolicy, this patch also add more checks
> > to warn (ASSERT) users any unreasonable setting combinations. For example,
> >
> >     PcdSetNxForStack == FALSE &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
> >
> >     PcdImageProtectionPolicy == 0 &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 << EfiRuntimeServicesData)) != 0
> >
> >     PcdImageProtectionPolicy == 0 &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) != 0
> >
> >     PcdImageProtectionPolicy == 0 &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
> >
> > In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
> > priority over PcdDxeNxMemoryProtectionPolicy.
> >
> > Cc: Star Zeng <star.zeng@intel.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Contributed-under: TianoCore Contribution Agreement 1.1
> > Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> > ---
> >  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
> >  MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
> >  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++++
> ++++++++++-
> >  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 +++++++++++++
> +
> >  4 files changed, 91 insertions(+), 3 deletions(-)
> >
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIp
> lPeim/DxeIpl.inf
> > index fd82657404..068e700074 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> > +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> > @@ -117,6 +117,8 @@
> >
> >  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIM
> ES_CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ##
> SOMETIMES_CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## SOME
> TIMES_CONSUMES
> >
> >  [Depex]
> >    gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/
> Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > index d28baa3615..9a97205ef8 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > @@ -245,7 +245,7 @@ ToBuildPageTable (
> >      return TRUE;
> >    }
> >
> > -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) {
> > +  if (ToEnableExecuteDisableFeature ()) {
> >      return TRUE;
> >    }
> >
> > @@ -436,7 +436,7 @@ HandOffToDxeCore (
> >      BuildPageTablesIa32Pae = ToBuildPageTable ();
> >      if (BuildPageTablesIa32Pae) {
> >        PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
> > -      if (IsExecuteDisableBitAvailable ()) {
> > +      if (ToEnableExecuteDisableFeature ()) {
> >          EnableExecuteDisableBit();
> >        }
> >      }
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg
> /Core/DxeIplPeim/X64/VirtualMemory.c
> > index 496e219913..253fe84223 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> > +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> > @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
> >    return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);
> >  }
> >
> > +/**
> > +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> > +
> > +  @retval TRUE    IA32_EFER.NXE should be enabled.
> > +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> > +
> > +**/
> > +BOOLEAN
> > +ToEnableExecuteDisableFeature (
> > +  VOID
> > +  )
> 
> I think we're over-complicating the name of this function. First, "To"
> looks unnecessary. Second, "Enable Execute Disable" is just an
> engineer's way to say "Disable Execution". Can we say right that:
> DisableExec()?
> 
> Or at least, if we consider "NX" a word in its own right, "EnableNX()"?

I prefer more general one. Let's use DisableExec().

> 
> > +{
> > +  if (!IsExecuteDisableBitAvailable ()) {
> > +    return FALSE;
> > +  }
> > +
> > +  //
> > +  // Normally stack is type of EfiBootServicesData. Disabling NX for stack
> > +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> > +  //
> 
> This comment is good.
> 
> > +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> 
> Please don't compare PcdGetBool() against TRUE or FALSE, just say
> PcdGetBool(), or !PcdGetBool().
> 
> > +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE)
>  != 0) {
> > +    DEBUG ((DEBUG_ERROR,
> > +            "ERROR: NX for stack is disabled but NX for its memory type is enabled
> !\r\n"));
> > +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> > +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_T
> YPE) != 0));
> > +  }
> 
> Please drop both the explicit "if", and the DEBUG message. Just keep the
> comment (which is already fine) and the ASSERT(). The ASSERT() will tell
> people where to look, and the comment will explain the assertion. Also,
> in a RELEASE build, the check should be eliminated entirely, but that
> might not work for the explicit "if" (dependent on compilers and/or
> fixed vs. dynamic PCDs).
> 
> Furthermore, keeping the logical negation operator as the outermost
> operator makes the code a lot harder to read. It's much better to just
> assert what we actually require, which is:
> 
>   (DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack
> 
> put differently,
> 
>   NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack
> 
> in C:
> 
>   ASSERT (
>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) ==
> 0 ||
>     PcdGetBool (PcdSetNxForStack)
>     );
> 

I don't have strong opinions on these. So let's do it your way.

> > +
> > +  //
> > +  // Image data section could be type of EfiLoaderData, EfiBootServicesData
> > +  // or EfiRuntimeServicesData. Disabling NX for image data but enabling NX
> > +  // for any those memory types doesn't make any sense.
> > +  //
> 
> The comment is good, I just suggest extending it with the origin of the
> image: "Disabling NX for image data (regardless of image origin) for any
> those memory types ...".
> 

Sure. I'll add it.

> > +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> > +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMOR
> Y_TYPE) != 0) {
> > +    DEBUG ((DEBUG_ERROR,
> > +            "ERROR: NX for image data is disabled but NX for its memory type(s) is
> enabled!\r\n"));
> > +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> > +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_ME
> MORY_TYPE) != 0));
> > +  }
> 
> Summarizing my points from before, here we should have:
> 
>   ASSERT (
>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TY
> PE) == 0 ||
>     PcdGet32 (PcdImageProtectionPolicy) == 3
>     );
> 
> That is,
> 
> - If we disable DxeNxMemoryProtectionPolicy for all of EfiLoaderData,
>   EfiBootServicesData, and EfiRuntimeServicesData, then any
>   ImageProtectionPolicy is fine.
> 
> - If we enable  DxeNxMemoryProtectionPolicy for any of EfiLoaderData,
>   EfiBootServicesData, and EfiRuntimeServicesData, then we require the
>   platform to set ImageProtectionPolicy regardless of image origin.
> 
> Thanks
> Laszlo
> 

Good catch. I missed that part. Thanks.

> > +
> > +  //
> > +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> > +  // Features controlled by Following PCDs need this feature to be enabled.
> > +  //
> > +  return (PcdGetBool (PcdSetNxForStack) ||
> > +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> > +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> > +}
> > +
> >  /**
> >    Enable Execute Disable Bit.
> >
> > @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
> >    //
> >    EnablePageTableProtection ((UINTN)PageMap, TRUE);
> >
> > -  if (PcdGetBool (PcdSetNxForStack)) {
> > +  //
> > +  // Set IA32_EFER.NXE if necessary.
> > +  //
> > +  if (ToEnableExecuteDisableFeature ()) {
> >      EnableExecuteDisableBit ();
> >    }
> >
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg
> /Core/DxeIplPeim/X64/VirtualMemory.h
> > index 85457ff937..9f152e6531 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> > +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> > @@ -179,6 +179,39 @@ typedef struct {
> >    UINTN           FreePages;
> >  } PAGE_TABLE_POOL;
> >
> > +//
> > +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table initializ
> ation.
> > +//
> > +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    /* 0x10 */
> > +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | /* 0x04
> */\
> > +                                     (1 << EfiBootServicesData) | /* 0x10 */\
> > +                                     (1 << EfiRuntimeServicesData)/* 0x40 */\
> > +                                    )                             /* 0x54 */
> > +
> > +/**
> > +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> > +
> > +  @retval TRUE    IA32_EFER.NXE should be enabled.
> > +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> > +
> > +**/
> > +BOOLEAN
> > +ToEnableExecuteDisableFeature (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  The function will check if Execute Disable Bit is available.
> > +
> > +  @retval TRUE      Execute Disable Bit is available.
> > +  @retval FALSE     Execute Disable Bit is not available.
> > +
> > +**/
> > +BOOLEAN
> > +IsExecuteDisableBitAvailable (
> > +  VOID
> > +  );
> > +
> >  /**
> >    Enable Execute Disable Bit.
> >
> >

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-17  2:11   ` Wang, Jian J
@ 2018-09-17  5:57     ` Zeng, Star
  2018-09-17 10:13       ` Laszlo Ersek
  0 siblings, 1 reply; 14+ messages in thread
From: Zeng, Star @ 2018-09-17  5:57 UTC (permalink / raw)
  To: Wang, Jian J, Laszlo Ersek, edk2-devel@lists.01.org
  Cc: Ard Biesheuvel, Ni, Ruiyu, Yao, Jiewen, Zeng, Star

How about we see the problem in another way?

If my understanding is correct, current discussion and patches think FALSE/0 means disable/clear NX, but that is not the fact.
According to the code implementation, FALSE/0 seems mean *AS IS* to do thing (no code to disable/clear NX).

PcdSetNxForStack
TRUE: Set NX for stack.
FALSE: No code to clear NX for stack.

PcdDxeNxMemoryProtectionPolicy
BITX 1: Set NX for that memory type.
BITX 0: No code to clear NX for that memory type.

PcdImageProtectionPolicy
BITX 1: Set NX for the image data section.
BITX 0: Not code to clear NX for the image data section.

So, how about we think one PCD just works for itself and it does not impact other PCDs to protect?
That means TRUE/1 is to protect and FALSE/0 is *AS IS* to do nothing.
The description of these PCDs could be enhancement if we think it is a good way to see the problem.


Thanks,
Star
-----Original Message-----
From: Wang, Jian J 
Sent: Monday, September 17, 2018 10:11 AM
To: Laszlo Ersek <lersek@redhat.com>; edk2-devel@lists.01.org
Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs

Laszlo,

Thanks for the comments.

Regards,
Jian

> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Friday, September 14, 2018 5:51 PM
> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel 
> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, 
> Jiewen <jiewen.yao@intel.com>
> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> I've got some comments on the code as well:
> 
> On 09/14/18 07:13, Jian J Wang wrote:
> > BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
> >
> > Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
> > confuses developers because following two other PCDs also need NXE
> > to be set, but actually not.
> >
> >     PcdDxeNxMemoryProtectionPolicy
> >     PcdImageProtectionPolicy
> >
> > This patch solves this issue by adding logic to enable IA32_EFER.NXE
> > if any of those PCDs have anything enabled.
> >
> > Due to the fact that NX memory type of stack (enabled by 
> >PcdSetNxForStack)
> > and image data section (enabled by PcdImageProtectionPolicy) are 
> >also
> > part of PcdDxeNxMemoryProtectionPolicy, this patch also add more 
> >checks
> > to warn (ASSERT) users any unreasonable setting combinations. For 
> >example,
> >
> >     PcdSetNxForStack == FALSE &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) 
> >!= 0
> >
> >     PcdImageProtectionPolicy == 0 &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 << 
> >EfiRuntimeServicesData)) != 0
> >
> >     PcdImageProtectionPolicy == 0 &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) 
> >!= 0
> >
> >     PcdImageProtectionPolicy == 0 &&
> >       (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
> >
> > In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
> > priority over PcdDxeNxMemoryProtectionPolicy.
> >
> > Cc: Star Zeng <star.zeng@intel.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Contributed-under: TianoCore Contribution Agreement 1.1
> > Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> > ---
> >  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
> >  MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
> >  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++++
> ++++++++++-
> >  MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 +++++++++++++
> +
> >  4 files changed, 91 insertions(+), 3 deletions(-)
> >
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf 
> b/MdeModulePkg/Core/DxeIp lPeim/DxeIpl.inf
> > index fd82657404..068e700074 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> > +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> > @@ -117,6 +117,8 @@
> >
> >  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## 
> >SOMETIM
> ES_CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ##
> SOMETIMES_CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## 
> >SOME
> TIMES_CONSUMES
> >
> >  [Depex]
> >    gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/ 
> Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > index d28baa3615..9a97205ef8 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > @@ -245,7 +245,7 @@ ToBuildPageTable (
> >      return TRUE;
> >    }
> >
> > -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable 
> >()) {
> > +  if (ToEnableExecuteDisableFeature ()) {
> >      return TRUE;
> >    }
> >
> > @@ -436,7 +436,7 @@ HandOffToDxeCore (
> >      BuildPageTablesIa32Pae = ToBuildPageTable ();
> >      if (BuildPageTablesIa32Pae) {
> >        PageTables = Create4GPageTablesIa32Pae (BaseOfStack, 
> >STACK_SIZE);
> > -      if (IsExecuteDisableBitAvailable ()) {
> > +      if (ToEnableExecuteDisableFeature ()) {
> >          EnableExecuteDisableBit();
> >        }
> >      }
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg 
> /Core/DxeIplPeim/X64/VirtualMemory.c
> > index 496e219913..253fe84223 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> > +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> > @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
> >    return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 
> >0);
> >  }
> >
> > +/**
> > +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> > +
> > +  @retval TRUE    IA32_EFER.NXE should be enabled.
> > +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> > +
> > +**/
> > +BOOLEAN
> > +ToEnableExecuteDisableFeature (
> > +  VOID
> > +  )
> 
> I think we're over-complicating the name of this function. First, "To"
> looks unnecessary. Second, "Enable Execute Disable" is just an 
> engineer's way to say "Disable Execution". Can we say right that:
> DisableExec()?
> 
> Or at least, if we consider "NX" a word in its own right, "EnableNX()"?

I prefer more general one. Let's use DisableExec().

> 
> > +{
> > +  if (!IsExecuteDisableBitAvailable ()) {
> > +    return FALSE;
> > +  }
> > +
> > +  //
> > +  // Normally stack is type of EfiBootServicesData. Disabling NX 
> >for stack
> > +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> > +  //
> 
> This comment is good.
> 
> > +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> 
> Please don't compare PcdGetBool() against TRUE or FALSE, just say 
> PcdGetBool(), or !PcdGetBool().
> 
> > +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
> >STACK_MEMORY_TYPE)
>  != 0) {
> > +    DEBUG ((DEBUG_ERROR,
> > +            "ERROR: NX for stack is disabled but NX for its memory 
> >type is enabled
> !\r\n"));
> > +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> > +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
> >STACK_MEMORY_T
> YPE) != 0));
> > +  }
> 
> Please drop both the explicit "if", and the DEBUG message. Just keep 
> the comment (which is already fine) and the ASSERT(). The ASSERT() 
> will tell people where to look, and the comment will explain the 
> assertion. Also, in a RELEASE build, the check should be eliminated 
> entirely, but that might not work for the explicit "if" (dependent on 
> compilers and/or fixed vs. dynamic PCDs).
> 
> Furthermore, keeping the logical negation operator as the outermost 
> operator makes the code a lot harder to read. It's much better to just 
> assert what we actually require, which is:
> 
>   (DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack
> 
> put differently,
> 
>   NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack
> 
> in C:
> 
>   ASSERT (
>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) ==
> 0 ||
>     PcdGetBool (PcdSetNxForStack)
>     );
> 

I don't have strong opinions on these. So let's do it your way.

> > +
> > +  //
> > +  // Image data section could be type of EfiLoaderData, 
> >EfiBootServicesData
> > +  // or EfiRuntimeServicesData. Disabling NX for image data but 
> >enabling NX
> > +  // for any those memory types doesn't make any sense.
> > +  //
> 
> The comment is good, I just suggest extending it with the origin of 
> the
> image: "Disabling NX for image data (regardless of image origin) for 
> any those memory types ...".
> 

Sure. I'll add it.

> > +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> > +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMOR
> Y_TYPE) != 0) {
> > +    DEBUG ((DEBUG_ERROR,
> > +            "ERROR: NX for image data is disabled but NX for its 
> >memory type(s) is
> enabled!\r\n"));
> > +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> > +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
> >IMAGE_DATA_ME
> MORY_TYPE) != 0));
> > +  }
> 
> Summarizing my points from before, here we should have:
> 
>   ASSERT (
>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TY
> PE) == 0 ||
>     PcdGet32 (PcdImageProtectionPolicy) == 3
>     );
> 
> That is,
> 
> - If we disable DxeNxMemoryProtectionPolicy for all of EfiLoaderData,
>   EfiBootServicesData, and EfiRuntimeServicesData, then any
>   ImageProtectionPolicy is fine.
> 
> - If we enable  DxeNxMemoryProtectionPolicy for any of EfiLoaderData,
>   EfiBootServicesData, and EfiRuntimeServicesData, then we require the
>   platform to set ImageProtectionPolicy regardless of image origin.
> 
> Thanks
> Laszlo
> 

Good catch. I missed that part. Thanks.

> > +
> > +  //
> > +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> > +  // Features controlled by Following PCDs need this feature to be enabled.
> > +  //
> > +  return (PcdGetBool (PcdSetNxForStack) ||
> > +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> > +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> > +}
> > +
> >  /**
> >    Enable Execute Disable Bit.
> >
> > @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
> >    //
> >    EnablePageTableProtection ((UINTN)PageMap, TRUE);
> >
> > -  if (PcdGetBool (PcdSetNxForStack)) {
> > +  //
> > +  // Set IA32_EFER.NXE if necessary.
> > +  //
> > +  if (ToEnableExecuteDisableFeature ()) {
> >      EnableExecuteDisableBit ();
> >    }
> >
> > diff --
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg 
> /Core/DxeIplPeim/X64/VirtualMemory.h
> > index 85457ff937..9f152e6531 100644
> > --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> > +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> > @@ -179,6 +179,39 @@ typedef struct {
> >    UINTN           FreePages;
> >  } PAGE_TABLE_POOL;
> >
> > +//
> > +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table 
> >initializ
> ation.
> > +//
> > +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    
> >/* 0x10 */
> > +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | 
> >/* 0x04
> */\
> > +                                     (1 << EfiBootServicesData) | 
> >/* 0x10 */\
> > +                                     (1 << 
> >EfiRuntimeServicesData)/* 0x40 */\
> > +                                    )                             
> >/* 0x54 */
> > +
> > +/**
> > +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> > +
> > +  @retval TRUE    IA32_EFER.NXE should be enabled.
> > +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> > +
> > +**/
> > +BOOLEAN
> > +ToEnableExecuteDisableFeature (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  The function will check if Execute Disable Bit is available.
> > +
> > +  @retval TRUE      Execute Disable Bit is available.
> > +  @retval FALSE     Execute Disable Bit is not available.
> > +
> > +**/
> > +BOOLEAN
> > +IsExecuteDisableBitAvailable (
> > +  VOID
> > +  );
> > +
> >  /**
> >    Enable Execute Disable Bit.
> >
> >

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-17  5:57     ` Zeng, Star
@ 2018-09-17 10:13       ` Laszlo Ersek
  2018-09-18  1:21         ` Wang, Jian J
  0 siblings, 1 reply; 14+ messages in thread
From: Laszlo Ersek @ 2018-09-17 10:13 UTC (permalink / raw)
  To: Zeng, Star, Wang, Jian J, edk2-devel@lists.01.org
  Cc: Ard Biesheuvel, Ni, Ruiyu, Yao, Jiewen

On 09/17/18 07:57, Zeng, Star wrote:
> How about we see the problem in another way?
> 
> If my understanding is correct, current discussion and patches think FALSE/0 means disable/clear NX, but that is not the fact.
> According to the code implementation, FALSE/0 seems mean *AS IS* to do thing (no code to disable/clear NX).
> 
> PcdSetNxForStack
> TRUE: Set NX for stack.
> FALSE: No code to clear NX for stack.
> 
> PcdDxeNxMemoryProtectionPolicy
> BITX 1: Set NX for that memory type.
> BITX 0: No code to clear NX for that memory type.
> 
> PcdImageProtectionPolicy
> BITX 1: Set NX for the image data section.
> BITX 0: Not code to clear NX for the image data section.
> 
> So, how about we think one PCD just works for itself and it does not impact other PCDs to protect?
> That means TRUE/1 is to protect and FALSE/0 is *AS IS* to do nothing.
> The description of these PCDs could be enhancement if we think it is a good way to see the problem.

Sure, that too could work for me, but then the documentation in the DEC
/ UNI files has to be really clear.

The initial worry for the current discussion was that some platform might
- protect e.g. BootServicesData type memory,
- not set PcdSetNxForStack,
- expect the stack to remain executable.

The actual results might surprise the platform owner.

If the documentation dispelled any possible misconceptions, I think your
idea could work too (and it would be a lot easier to code).

Thanks
Laszlo


> 
> 
> Thanks,
> Star
> -----Original Message-----
> From: Wang, Jian J 
> Sent: Monday, September 17, 2018 10:11 AM
> To: Laszlo Ersek <lersek@redhat.com>; edk2-devel@lists.01.org
> Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> Laszlo,
> 
> Thanks for the comments.
> 
> Regards,
> Jian
> 
>> -----Original Message-----
>> From: Laszlo Ersek [mailto:lersek@redhat.com]
>> Sent: Friday, September 14, 2018 5:51 PM
>> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
>> Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel 
>> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, 
>> Jiewen <jiewen.yao@intel.com>
>> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
>>
>> I've got some comments on the code as well:
>>
>> On 09/14/18 07:13, Jian J Wang wrote:
>>>  BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
>>>
>>>  Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
>>>  confuses developers because following two other PCDs also need NXE
>>>  to be set, but actually not.
>>>
>>>      PcdDxeNxMemoryProtectionPolicy
>>>      PcdImageProtectionPolicy
>>>
>>>  This patch solves this issue by adding logic to enable IA32_EFER.NXE
>>>  if any of those PCDs have anything enabled.
>>>
>>>  Due to the fact that NX memory type of stack (enabled by 
>>> PcdSetNxForStack)
>>>  and image data section (enabled by PcdImageProtectionPolicy) are 
>>> also
>>>  part of PcdDxeNxMemoryProtectionPolicy, this patch also add more 
>>> checks
>>>  to warn (ASSERT) users any unreasonable setting combinations. For 
>>> example,
>>>
>>>      PcdSetNxForStack == FALSE &&
>>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) 
>>> != 0
>>>
>>>      PcdImageProtectionPolicy == 0 &&
>>>        (PcdDxeNxMemoryProtectionPolicy & (1 << 
>>> EfiRuntimeServicesData)) != 0
>>>
>>>      PcdImageProtectionPolicy == 0 &&
>>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData)) 
>>> != 0
>>>
>>>      PcdImageProtectionPolicy == 0 &&
>>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
>>>
>>>  In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
>>>  priority over PcdDxeNxMemoryProtectionPolicy.
>>>
>>>  Cc: Star Zeng <star.zeng@intel.com>
>>>  Cc: Laszlo Ersek <lersek@redhat.com>
>>>  Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>>  Cc: Ruiyu Ni <ruiyu.ni@intel.com>
>>>  Cc: Jiewen Yao <jiewen.yao@intel.com>
>>>  Contributed-under: TianoCore Contribution Agreement 1.1
>>>  Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
>>>  ---
>>>   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
>>>   MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
>>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++++
>> ++++++++++-
>>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 +++++++++++++
>> +
>>>   4 files changed, 91 insertions(+), 3 deletions(-)
>>>
>>>  diff --
>> git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf 
>> b/MdeModulePkg/Core/DxeIp lPeim/DxeIpl.inf
>>>  index fd82657404..068e700074 100644
>>>  --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>>>  +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>>>  @@ -117,6 +117,8 @@
>>>
>>>   [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>>>     gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## 
>>> SOMETIM
>> ES_CONSUMES
>>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ##
>> SOMETIMES_CONSUMES
>>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## 
>>> SOME
>> TIMES_CONSUMES
>>>
>>>   [Depex]
>>>     gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
>>>  diff --
>> git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/ 
>> Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>>>  index d28baa3615..9a97205ef8 100644
>>>  --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>>>  +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
>>>  @@ -245,7 +245,7 @@ ToBuildPageTable (
>>>       return TRUE;
>>>     }
>>>
>>>  -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable 
>>> ()) {
>>>  +  if (ToEnableExecuteDisableFeature ()) {
>>>       return TRUE;
>>>     }
>>>
>>>  @@ -436,7 +436,7 @@ HandOffToDxeCore (
>>>       BuildPageTablesIa32Pae = ToBuildPageTable ();
>>>       if (BuildPageTablesIa32Pae) {
>>>         PageTables = Create4GPageTablesIa32Pae (BaseOfStack, 
>>> STACK_SIZE);
>>>  -      if (IsExecuteDisableBitAvailable ()) {
>>>  +      if (ToEnableExecuteDisableFeature ()) {
>>>           EnableExecuteDisableBit();
>>>         }
>>>       }
>>>  diff --
>> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg 
>> /Core/DxeIplPeim/X64/VirtualMemory.c
>>>  index 496e219913..253fe84223 100644
>>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>>>  @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
>>>     return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 
>>> 0);
>>>   }
>>>
>>>  +/**
>>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
>>>  +
>>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
>>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
>>>  +
>>>  +**/
>>>  +BOOLEAN
>>>  +ToEnableExecuteDisableFeature (
>>>  +  VOID
>>>  +  )
>>
>> I think we're over-complicating the name of this function. First, "To"
>> looks unnecessary. Second, "Enable Execute Disable" is just an 
>> engineer's way to say "Disable Execution". Can we say right that:
>> DisableExec()?
>>
>> Or at least, if we consider "NX" a word in its own right, "EnableNX()"?
> 
> I prefer more general one. Let's use DisableExec().
> 
>>
>>>  +{
>>>  +  if (!IsExecuteDisableBitAvailable ()) {
>>>  +    return FALSE;
>>>  +  }
>>>  +
>>>  +  //
>>>  +  // Normally stack is type of EfiBootServicesData. Disabling NX 
>>> for stack
>>>  +  // but enabling NX for EfiBootServicesData doesn't make any sense.
>>>  +  //
>>
>> This comment is good.
>>
>>>  +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
>>
>> Please don't compare PcdGetBool() against TRUE or FALSE, just say 
>> PcdGetBool(), or !PcdGetBool().
>>
>>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
>>> STACK_MEMORY_TYPE)
>>  != 0) {
>>>  +    DEBUG ((DEBUG_ERROR,
>>>  +            "ERROR: NX for stack is disabled but NX for its memory 
>>> type is enabled
>> !\r\n"));
>>>  +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
>>>  +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
>>> STACK_MEMORY_T
>> YPE) != 0));
>>>  +  }
>>
>> Please drop both the explicit "if", and the DEBUG message. Just keep 
>> the comment (which is already fine) and the ASSERT(). The ASSERT() 
>> will tell people where to look, and the comment will explain the 
>> assertion. Also, in a RELEASE build, the check should be eliminated 
>> entirely, but that might not work for the explicit "if" (dependent on 
>> compilers and/or fixed vs. dynamic PCDs).
>>
>> Furthermore, keeping the logical negation operator as the outermost 
>> operator makes the code a lot harder to read. It's much better to just 
>> assert what we actually require, which is:
>>
>>   (DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack
>>
>> put differently,
>>
>>   NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack
>>
>> in C:
>>
>>   ASSERT (
>>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE) ==
>> 0 ||
>>     PcdGetBool (PcdSetNxForStack)
>>     );
>>
> 
> I don't have strong opinions on these. So let's do it your way.
> 
>>>  +
>>>  +  //
>>>  +  // Image data section could be type of EfiLoaderData, 
>>> EfiBootServicesData
>>>  +  // or EfiRuntimeServicesData. Disabling NX for image data but 
>>> enabling NX
>>>  +  // for any those memory types doesn't make any sense.
>>>  +  //
>>
>> The comment is good, I just suggest extending it with the origin of 
>> the
>> image: "Disabling NX for image data (regardless of image origin) for 
>> any those memory types ...".
>>
> 
> Sure. I'll add it.
> 
>>>  +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
>>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMOR
>> Y_TYPE) != 0) {
>>>  +    DEBUG ((DEBUG_ERROR,
>>>  +            "ERROR: NX for image data is disabled but NX for its 
>>> memory type(s) is
>> enabled!\r\n"));
>>>  +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
>>>  +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
>>> IMAGE_DATA_ME
>> MORY_TYPE) != 0));
>>>  +  }
>>
>> Summarizing my points from before, here we should have:
>>
>>   ASSERT (
>>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY_TY
>> PE) == 0 ||
>>     PcdGet32 (PcdImageProtectionPolicy) == 3
>>     );
>>
>> That is,
>>
>> - If we disable DxeNxMemoryProtectionPolicy for all of EfiLoaderData,
>>   EfiBootServicesData, and EfiRuntimeServicesData, then any
>>   ImageProtectionPolicy is fine.
>>
>> - If we enable  DxeNxMemoryProtectionPolicy for any of EfiLoaderData,
>>   EfiBootServicesData, and EfiRuntimeServicesData, then we require the
>>   platform to set ImageProtectionPolicy regardless of image origin.
>>
>> Thanks
>> Laszlo
>>
> 
> Good catch. I missed that part. Thanks.
> 
>>>  +
>>>  +  //
>>>  +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
>>>  +  // Features controlled by Following PCDs need this feature to be enabled.
>>>  +  //
>>>  +  return (PcdGetBool (PcdSetNxForStack) ||
>>>  +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
>>>  +          PcdGet32 (PcdImageProtectionPolicy) != 0);
>>>  +}
>>>  +
>>>   /**
>>>     Enable Execute Disable Bit.
>>>
>>>  @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
>>>     //
>>>     EnablePageTableProtection ((UINTN)PageMap, TRUE);
>>>
>>>  -  if (PcdGetBool (PcdSetNxForStack)) {
>>>  +  //
>>>  +  // Set IA32_EFER.NXE if necessary.
>>>  +  //
>>>  +  if (ToEnableExecuteDisableFeature ()) {
>>>       EnableExecuteDisableBit ();
>>>     }
>>>
>>>  diff --
>> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg 
>> /Core/DxeIplPeim/X64/VirtualMemory.h
>>>  index 85457ff937..9f152e6531 100644
>>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
>>>  @@ -179,6 +179,39 @@ typedef struct {
>>>     UINTN           FreePages;
>>>   } PAGE_TABLE_POOL;
>>>
>>>  +//
>>>  +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table 
>>> initializ
>> ation.
>>>  +//
>>>  +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)    
>>> /* 0x10 */
>>>  +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       | 
>>> /* 0x04
>> */\
>>>  +                                     (1 << EfiBootServicesData) | 
>>> /* 0x10 */\
>>>  +                                     (1 << 
>>> EfiRuntimeServicesData)/* 0x40 */\
>>>  +                                    )                             
>>> /* 0x54 */
>>>  +
>>>  +/**
>>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
>>>  +
>>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
>>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
>>>  +
>>>  +**/
>>>  +BOOLEAN
>>>  +ToEnableExecuteDisableFeature (
>>>  +  VOID
>>>  +  );
>>>  +
>>>  +/**
>>>  +  The function will check if Execute Disable Bit is available.
>>>  +
>>>  +  @retval TRUE      Execute Disable Bit is available.
>>>  +  @retval FALSE     Execute Disable Bit is not available.
>>>  +
>>>  +**/
>>>  +BOOLEAN
>>>  +IsExecuteDisableBitAvailable (
>>>  +  VOID
>>>  +  );
>>>  +
>>>   /**
>>>     Enable Execute Disable Bit.
>>>
>>>



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-17 10:13       ` Laszlo Ersek
@ 2018-09-18  1:21         ` Wang, Jian J
  2018-09-18  8:46           ` Zeng, Star
  0 siblings, 1 reply; 14+ messages in thread
From: Wang, Jian J @ 2018-09-18  1:21 UTC (permalink / raw)
  To: Laszlo Ersek, Zeng, Star, edk2-devel@lists.01.org
  Cc: Ard Biesheuvel, Ni, Ruiyu, Yao, Jiewen

I have no strong opinion for this proposal. But if we decide to do it finally,
I'd suggest to add some warning messages for any probably surprising setting
combinations.

Regards,
Jian


> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Monday, September 17, 2018 6:14 PM
> To: Zeng, Star <star.zeng@intel.com>; Wang, Jian J <jian.j.wang@intel.com>;
> edk2-devel@lists.01.org
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> Yao, Jiewen <jiewen.yao@intel.com>
> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> On 09/17/18 07:57, Zeng, Star wrote:
> > How about we see the problem in another way?
> >
> > If my understanding is correct, current discussion and patches think FALSE/0
> means disable/clear NX, but that is not the fact.
> > According to the code implementation, FALSE/0 seems mean *AS IS* to do
> thing (no code to disable/clear NX).
> >
> > PcdSetNxForStack
> > TRUE: Set NX for stack.
> > FALSE: No code to clear NX for stack.
> >
> > PcdDxeNxMemoryProtectionPolicy
> > BITX 1: Set NX for that memory type.
> > BITX 0: No code to clear NX for that memory type.
> >
> > PcdImageProtectionPolicy
> > BITX 1: Set NX for the image data section.
> > BITX 0: Not code to clear NX for the image data section.
> >
> > So, how about we think one PCD just works for itself and it does not impact
> other PCDs to protect?
> > That means TRUE/1 is to protect and FALSE/0 is *AS IS* to do nothing.
> > The description of these PCDs could be enhancement if we think it is a good
> way to see the problem.
> 
> Sure, that too could work for me, but then the documentation in the DEC
> / UNI files has to be really clear.
> 
> The initial worry for the current discussion was that some platform might
> - protect e.g. BootServicesData type memory,
> - not set PcdSetNxForStack,
> - expect the stack to remain executable.
> 
> The actual results might surprise the platform owner.
> 
> If the documentation dispelled any possible misconceptions, I think your
> idea could work too (and it would be a lot easier to code).
> 
> Thanks
> Laszlo
> 
> 
> >
> >
> > Thanks,
> > Star
> > -----Original Message-----
> > From: Wang, Jian J
> > Sent: Monday, September 17, 2018 10:11 AM
> > To: Laszlo Ersek <lersek@redhat.com>; edk2-devel@lists.01.org
> > Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel
> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen
> <jiewen.yao@intel.com>
> > Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> >
> > Laszlo,
> >
> > Thanks for the comments.
> >
> > Regards,
> > Jian
> >
> >> -----Original Message-----
> >> From: Laszlo Ersek [mailto:lersek@redhat.com]
> >> Sent: Friday, September 14, 2018 5:51 PM
> >> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> >> Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel
> >> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao,
> >> Jiewen <jiewen.yao@intel.com>
> >> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> >>
> >> I've got some comments on the code as well:
> >>
> >> On 09/14/18 07:13, Jian J Wang wrote:
> >>>  BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
> >>>
> >>>  Currently IA32_EFER.NXE is only set against PcdSetNxForStack. This
> >>>  confuses developers because following two other PCDs also need NXE
> >>>  to be set, but actually not.
> >>>
> >>>      PcdDxeNxMemoryProtectionPolicy
> >>>      PcdImageProtectionPolicy
> >>>
> >>>  This patch solves this issue by adding logic to enable IA32_EFER.NXE
> >>>  if any of those PCDs have anything enabled.
> >>>
> >>>  Due to the fact that NX memory type of stack (enabled by
> >>> PcdSetNxForStack)
> >>>  and image data section (enabled by PcdImageProtectionPolicy) are
> >>> also
> >>>  part of PcdDxeNxMemoryProtectionPolicy, this patch also add more
> >>> checks
> >>>  to warn (ASSERT) users any unreasonable setting combinations. For
> >>> example,
> >>>
> >>>      PcdSetNxForStack == FALSE &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData))
> >>> != 0
> >>>
> >>>      PcdImageProtectionPolicy == 0 &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<
> >>> EfiRuntimeServicesData)) != 0
> >>>
> >>>      PcdImageProtectionPolicy == 0 &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiBootServicesData))
> >>> != 0
> >>>
> >>>      PcdImageProtectionPolicy == 0 &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
> >>>
> >>>  In other words, PcdSetNxForStack and PcdImageProtectionPolicy have
> >>>  priority over PcdDxeNxMemoryProtectionPolicy.
> >>>
> >>>  Cc: Star Zeng <star.zeng@intel.com>
> >>>  Cc: Laszlo Ersek <lersek@redhat.com>
> >>>  Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >>>  Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> >>>  Cc: Jiewen Yao <jiewen.yao@intel.com>
> >>>  Contributed-under: TianoCore Contribution Agreement 1.1
> >>>  Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> >>>  ---
> >>>   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
> >>>   MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
> >>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 +++++++++++
> ++
> >> ++++++++++-
> >>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 +++++++++++
> ++
> >> +
> >>>   4 files changed, 91 insertions(+), 3 deletions(-)
> >>>
> >>>  diff --
> >> git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> >> b/MdeModulePkg/Core/DxeIp lPeim/DxeIpl.inf
> >>>  index fd82657404..068e700074 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> >>>  @@ -117,6 +117,8 @@
> >>>
> >>>   [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
> >>>     gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ##
> >>> SOMETIM
> >> ES_CONSUMES
> >>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy
> ##
> >> SOMETIMES_CONSUMES
> >>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ##
> >>> SOME
> >> TIMES_CONSUMES
> >>>
> >>>   [Depex]
> >>>     gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> >>>  diff --
> >>
> git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/
> >> Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> >>>  index d28baa3615..9a97205ef8 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> >>>  @@ -245,7 +245,7 @@ ToBuildPageTable (
> >>>       return TRUE;
> >>>     }
> >>>
> >>>  -  if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable
> >>> ()) {
> >>>  +  if (ToEnableExecuteDisableFeature ()) {
> >>>       return TRUE;
> >>>     }
> >>>
> >>>  @@ -436,7 +436,7 @@ HandOffToDxeCore (
> >>>       BuildPageTablesIa32Pae = ToBuildPageTable ();
> >>>       if (BuildPageTablesIa32Pae) {
> >>>         PageTables = Create4GPageTablesIa32Pae (BaseOfStack,
> >>> STACK_SIZE);
> >>>  -      if (IsExecuteDisableBitAvailable ()) {
> >>>  +      if (ToEnableExecuteDisableFeature ()) {
> >>>           EnableExecuteDisableBit();
> >>>         }
> >>>       }
> >>>  diff --
> >>
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg
> >> /Core/DxeIplPeim/X64/VirtualMemory.c
> >>>  index 496e219913..253fe84223 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> >>>  @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
> >>>     return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) !=
> >>> 0);
> >>>   }
> >>>
> >>>  +/**
> >>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> >>>  +
> >>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
> >>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> >>>  +
> >>>  +**/
> >>>  +BOOLEAN
> >>>  +ToEnableExecuteDisableFeature (
> >>>  +  VOID
> >>>  +  )
> >>
> >> I think we're over-complicating the name of this function. First, "To"
> >> looks unnecessary. Second, "Enable Execute Disable" is just an
> >> engineer's way to say "Disable Execution". Can we say right that:
> >> DisableExec()?
> >>
> >> Or at least, if we consider "NX" a word in its own right, "EnableNX()"?
> >
> > I prefer more general one. Let's use DisableExec().
> >
> >>
> >>>  +{
> >>>  +  if (!IsExecuteDisableBitAvailable ()) {
> >>>  +    return FALSE;
> >>>  +  }
> >>>  +
> >>>  +  //
> >>>  +  // Normally stack is type of EfiBootServicesData. Disabling NX
> >>> for stack
> >>>  +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> >>>  +  //
> >>
> >> This comment is good.
> >>
> >>>  +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> >>
> >> Please don't compare PcdGetBool() against TRUE or FALSE, just say
> >> PcdGetBool(), or !PcdGetBool().
> >>
> >>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> >>> STACK_MEMORY_TYPE)
> >>  != 0) {
> >>>  +    DEBUG ((DEBUG_ERROR,
> >>>  +            "ERROR: NX for stack is disabled but NX for its memory
> >>> type is enabled
> >> !\r\n"));
> >>>  +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> >>>  +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> >>> STACK_MEMORY_T
> >> YPE) != 0));
> >>>  +  }
> >>
> >> Please drop both the explicit "if", and the DEBUG message. Just keep
> >> the comment (which is already fine) and the ASSERT(). The ASSERT()
> >> will tell people where to look, and the comment will explain the
> >> assertion. Also, in a RELEASE build, the check should be eliminated
> >> entirely, but that might not work for the explicit "if" (dependent on
> >> compilers and/or fixed vs. dynamic PCDs).
> >>
> >> Furthermore, keeping the logical negation operator as the outermost
> >> operator makes the code a lot harder to read. It's much better to just
> >> assert what we actually require, which is:
> >>
> >>   (DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack
> >>
> >> put differently,
> >>
> >>   NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack
> >>
> >> in C:
> >>
> >>   ASSERT (
> >>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE)
> ==
> >> 0 ||
> >>     PcdGetBool (PcdSetNxForStack)
> >>     );
> >>
> >
> > I don't have strong opinions on these. So let's do it your way.
> >
> >>>  +
> >>>  +  //
> >>>  +  // Image data section could be type of EfiLoaderData,
> >>> EfiBootServicesData
> >>>  +  // or EfiRuntimeServicesData. Disabling NX for image data but
> >>> enabling NX
> >>>  +  // for any those memory types doesn't make any sense.
> >>>  +  //
> >>
> >> The comment is good, I just suggest extending it with the origin of
> >> the
> >> image: "Disabling NX for image data (regardless of image origin) for
> >> any those memory types ...".
> >>
> >
> > Sure. I'll add it.
> >
> >>>  +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> >>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEM
> OR
> >> Y_TYPE) != 0) {
> >>>  +    DEBUG ((DEBUG_ERROR,
> >>>  +            "ERROR: NX for image data is disabled but NX for its
> >>> memory type(s) is
> >> enabled!\r\n"));
> >>>  +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> >>>  +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> >>> IMAGE_DATA_ME
> >> MORY_TYPE) != 0));
> >>>  +  }
> >>
> >> Summarizing my points from before, here we should have:
> >>
> >>   ASSERT (
> >>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY
> _TY
> >> PE) == 0 ||
> >>     PcdGet32 (PcdImageProtectionPolicy) == 3
> >>     );
> >>
> >> That is,
> >>
> >> - If we disable DxeNxMemoryProtectionPolicy for all of EfiLoaderData,
> >>   EfiBootServicesData, and EfiRuntimeServicesData, then any
> >>   ImageProtectionPolicy is fine.
> >>
> >> - If we enable  DxeNxMemoryProtectionPolicy for any of EfiLoaderData,
> >>   EfiBootServicesData, and EfiRuntimeServicesData, then we require the
> >>   platform to set ImageProtectionPolicy regardless of image origin.
> >>
> >> Thanks
> >> Laszlo
> >>
> >
> > Good catch. I missed that part. Thanks.
> >
> >>>  +
> >>>  +  //
> >>>  +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> >>>  +  // Features controlled by Following PCDs need this feature to be enabled.
> >>>  +  //
> >>>  +  return (PcdGetBool (PcdSetNxForStack) ||
> >>>  +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> >>>  +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> >>>  +}
> >>>  +
> >>>   /**
> >>>     Enable Execute Disable Bit.
> >>>
> >>>  @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
> >>>     //
> >>>     EnablePageTableProtection ((UINTN)PageMap, TRUE);
> >>>
> >>>  -  if (PcdGetBool (PcdSetNxForStack)) {
> >>>  +  //
> >>>  +  // Set IA32_EFER.NXE if necessary.
> >>>  +  //
> >>>  +  if (ToEnableExecuteDisableFeature ()) {
> >>>       EnableExecuteDisableBit ();
> >>>     }
> >>>
> >>>  diff --
> >>
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg
> >> /Core/DxeIplPeim/X64/VirtualMemory.h
> >>>  index 85457ff937..9f152e6531 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> >>>  @@ -179,6 +179,39 @@ typedef struct {
> >>>     UINTN           FreePages;
> >>>   } PAGE_TABLE_POOL;
> >>>
> >>>  +//
> >>>  +// Bit field repsentations of some EFI_MEMORY_TYPE, for page table
> >>> initializ
> >> ation.
> >>>  +//
> >>>  +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)
> >>> /* 0x10 */
> >>>  +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       |
> >>> /* 0x04
> >> */\
> >>>  +                                     (1 << EfiBootServicesData) |
> >>> /* 0x10 */\
> >>>  +                                     (1 <<
> >>> EfiRuntimeServicesData)/* 0x40 */\
> >>>  +                                    )
> >>> /* 0x54 */
> >>>  +
> >>>  +/**
> >>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> >>>  +
> >>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
> >>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> >>>  +
> >>>  +**/
> >>>  +BOOLEAN
> >>>  +ToEnableExecuteDisableFeature (
> >>>  +  VOID
> >>>  +  );
> >>>  +
> >>>  +/**
> >>>  +  The function will check if Execute Disable Bit is available.
> >>>  +
> >>>  +  @retval TRUE      Execute Disable Bit is available.
> >>>  +  @retval FALSE     Execute Disable Bit is not available.
> >>>  +
> >>>  +**/
> >>>  +BOOLEAN
> >>>  +IsExecuteDisableBitAvailable (
> >>>  +  VOID
> >>>  +  );
> >>>  +
> >>>   /**
> >>>     Enable Execute Disable Bit.
> >>>
> >>>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-18  1:21         ` Wang, Jian J
@ 2018-09-18  8:46           ` Zeng, Star
  2018-09-19  9:13             ` Wang, Jian J
  0 siblings, 1 reply; 14+ messages in thread
From: Zeng, Star @ 2018-09-18  8:46 UTC (permalink / raw)
  To: Wang, Jian J, Laszlo Ersek, edk2-devel@lists.01.org
  Cc: Ard Biesheuvel, Ni, Ruiyu, Yao, Jiewen, Zeng, Star

I totally agree adding more clear documentation in dec and uni.
My only concern is that the warning message (by checking the combinations) to explain in c may bring more confusion.
Anyway, if we can have the warning message to make the things more clear, I definitely agree it. :)


Thanks,
Star
-----Original Message-----
From: Wang, Jian J 
Sent: Tuesday, September 18, 2018 9:22 AM
To: Laszlo Ersek <lersek@redhat.com>; Zeng, Star <star.zeng@intel.com>; edk2-devel@lists.01.org
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs

I have no strong opinion for this proposal. But if we decide to do it finally, I'd suggest to add some warning messages for any probably surprising setting combinations.

Regards,
Jian


> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Monday, September 17, 2018 6:14 PM
> To: Zeng, Star <star.zeng@intel.com>; Wang, Jian J 
> <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu 
> <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> On 09/17/18 07:57, Zeng, Star wrote:
> > How about we see the problem in another way?
> >
> > If my understanding is correct, current discussion and patches think 
> > FALSE/0
> means disable/clear NX, but that is not the fact.
> > According to the code implementation, FALSE/0 seems mean *AS IS* to 
> > do
> thing (no code to disable/clear NX).
> >
> > PcdSetNxForStack
> > TRUE: Set NX for stack.
> > FALSE: No code to clear NX for stack.
> >
> > PcdDxeNxMemoryProtectionPolicy
> > BITX 1: Set NX for that memory type.
> > BITX 0: No code to clear NX for that memory type.
> >
> > PcdImageProtectionPolicy
> > BITX 1: Set NX for the image data section.
> > BITX 0: Not code to clear NX for the image data section.
> >
> > So, how about we think one PCD just works for itself and it does not 
> > impact
> other PCDs to protect?
> > That means TRUE/1 is to protect and FALSE/0 is *AS IS* to do nothing.
> > The description of these PCDs could be enhancement if we think it is 
> > a good
> way to see the problem.
> 
> Sure, that too could work for me, but then the documentation in the 
> DEC / UNI files has to be really clear.
> 
> The initial worry for the current discussion was that some platform 
> might
> - protect e.g. BootServicesData type memory,
> - not set PcdSetNxForStack,
> - expect the stack to remain executable.
> 
> The actual results might surprise the platform owner.
> 
> If the documentation dispelled any possible misconceptions, I think 
> your idea could work too (and it would be a lot easier to code).
> 
> Thanks
> Laszlo
> 
> 
> >
> >
> > Thanks,
> > Star
> > -----Original Message-----
> > From: Wang, Jian J
> > Sent: Monday, September 17, 2018 10:11 AM
> > To: Laszlo Ersek <lersek@redhat.com>; edk2-devel@lists.01.org
> > Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel
> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, 
> Jiewen <jiewen.yao@intel.com>
> > Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related 
> > PCDs
> >
> > Laszlo,
> >
> > Thanks for the comments.
> >
> > Regards,
> > Jian
> >
> >> -----Original Message-----
> >> From: Laszlo Ersek [mailto:lersek@redhat.com]
> >> Sent: Friday, September 14, 2018 5:51 PM
> >> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> >> Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel 
> >> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, 
> >> Jiewen <jiewen.yao@intel.com>
> >> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related 
> >> PCDs
> >>
> >> I've got some comments on the code as well:
> >>
> >> On 09/14/18 07:13, Jian J Wang wrote:
> >>>  BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
> >>>
> >>>  Currently IA32_EFER.NXE is only set against PcdSetNxForStack. 
> >>> This
> >>>  confuses developers because following two other PCDs also need 
> >>> NXE
> >>>  to be set, but actually not.
> >>>
> >>>      PcdDxeNxMemoryProtectionPolicy
> >>>      PcdImageProtectionPolicy
> >>>
> >>>  This patch solves this issue by adding logic to enable 
> >>> IA32_EFER.NXE
> >>>  if any of those PCDs have anything enabled.
> >>>
> >>>  Due to the fact that NX memory type of stack (enabled by
> >>> PcdSetNxForStack)
> >>>  and image data section (enabled by PcdImageProtectionPolicy) are 
> >>> also
> >>>  part of PcdDxeNxMemoryProtectionPolicy, this patch also add more 
> >>> checks
> >>>  to warn (ASSERT) users any unreasonable setting combinations. For 
> >>> example,
> >>>
> >>>      PcdSetNxForStack == FALSE &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 
> >>> <<EfiBootServicesData)) != 0
> >>>
> >>>      PcdImageProtectionPolicy == 0 &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<
> >>> EfiRuntimeServicesData)) != 0
> >>>
> >>>      PcdImageProtectionPolicy == 0 &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 
> >>> <<EfiBootServicesData)) != 0
> >>>
> >>>      PcdImageProtectionPolicy == 0 &&
> >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
> >>>
> >>>  In other words, PcdSetNxForStack and PcdImageProtectionPolicy 
> >>> have
> >>>  priority over PcdDxeNxMemoryProtectionPolicy.
> >>>
> >>>  Cc: Star Zeng <star.zeng@intel.com>
> >>>  Cc: Laszlo Ersek <lersek@redhat.com>
> >>>  Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >>>  Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> >>>  Cc: Jiewen Yao <jiewen.yao@intel.com>
> >>>  Contributed-under: TianoCore Contribution Agreement 1.1
> >>>  Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> >>>  ---
> >>>   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
> >>>   MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
> >>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55 
> >>> +++++++++++
> ++
> >> ++++++++++-
> >>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33 
> >>> +++++++++++
> ++
> >> +
> >>>   4 files changed, 91 insertions(+), 3 deletions(-)
> >>>
> >>>  diff --
> >> git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> >> b/MdeModulePkg/Core/DxeIp lPeim/DxeIpl.inf
> >>>  index fd82657404..068e700074 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> >>>  @@ -117,6 +117,8 @@
> >>>
> >>>   [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
> >>>     gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               
> >>> ## SOMETIM
> >> ES_CONSUMES
> >>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy
> ##
> >> SOMETIMES_CONSUMES
> >>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       
> >>> ## SOME
> >> TIMES_CONSUMES
> >>>
> >>>   [Depex]
> >>>     gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> >>>  diff --
> >>
> git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/
> >> Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> >>>  index d28baa3615..9a97205ef8 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> >>>  @@ -245,7 +245,7 @@ ToBuildPageTable (
> >>>       return TRUE;
> >>>     }
> >>>
> >>>  -  if (PcdGetBool (PcdSetNxForStack) && 
> >>> IsExecuteDisableBitAvailable
> >>> ()) {
> >>>  +  if (ToEnableExecuteDisableFeature ()) {
> >>>       return TRUE;
> >>>     }
> >>>
> >>>  @@ -436,7 +436,7 @@ HandOffToDxeCore (
> >>>       BuildPageTablesIa32Pae = ToBuildPageTable ();
> >>>       if (BuildPageTablesIa32Pae) {
> >>>         PageTables = Create4GPageTablesIa32Pae (BaseOfStack, 
> >>> STACK_SIZE);
> >>>  -      if (IsExecuteDisableBitAvailable ()) {
> >>>  +      if (ToEnableExecuteDisableFeature ()) {
> >>>           EnableExecuteDisableBit();
> >>>         }
> >>>       }
> >>>  diff --
> >>
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg
> >> /Core/DxeIplPeim/X64/VirtualMemory.c
> >>>  index 496e219913..253fe84223 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> >>>  @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
> >>>     return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) 
> >>> != 0);
> >>>   }
> >>>
> >>>  +/**
> >>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> >>>  +
> >>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
> >>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> >>>  +
> >>>  +**/
> >>>  +BOOLEAN
> >>>  +ToEnableExecuteDisableFeature (
> >>>  +  VOID
> >>>  +  )
> >>
> >> I think we're over-complicating the name of this function. First, "To"
> >> looks unnecessary. Second, "Enable Execute Disable" is just an 
> >> engineer's way to say "Disable Execution". Can we say right that:
> >> DisableExec()?
> >>
> >> Or at least, if we consider "NX" a word in its own right, "EnableNX()"?
> >
> > I prefer more general one. Let's use DisableExec().
> >
> >>
> >>>  +{
> >>>  +  if (!IsExecuteDisableBitAvailable ()) {
> >>>  +    return FALSE;
> >>>  +  }
> >>>  +
> >>>  +  //
> >>>  +  // Normally stack is type of EfiBootServicesData. Disabling NX 
> >>> for stack
> >>>  +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> >>>  +  //
> >>
> >> This comment is good.
> >>
> >>>  +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> >>
> >> Please don't compare PcdGetBool() against TRUE or FALSE, just say 
> >> PcdGetBool(), or !PcdGetBool().
> >>
> >>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> >>> STACK_MEMORY_TYPE)
> >>  != 0) {
> >>>  +    DEBUG ((DEBUG_ERROR,
> >>>  +            "ERROR: NX for stack is disabled but NX for its 
> >>> memory type is enabled
> >> !\r\n"));
> >>>  +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> >>>  +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
> >>> STACK_MEMORY_T
> >> YPE) != 0));
> >>>  +  }
> >>
> >> Please drop both the explicit "if", and the DEBUG message. Just 
> >> keep the comment (which is already fine) and the ASSERT(). The 
> >> ASSERT() will tell people where to look, and the comment will 
> >> explain the assertion. Also, in a RELEASE build, the check should 
> >> be eliminated entirely, but that might not work for the explicit 
> >> "if" (dependent on compilers and/or fixed vs. dynamic PCDs).
> >>
> >> Furthermore, keeping the logical negation operator as the outermost 
> >> operator makes the code a lot harder to read. It's much better to 
> >> just assert what we actually require, which is:
> >>
> >>   (DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack
> >>
> >> put differently,
> >>
> >>   NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack
> >>
> >> in C:
> >>
> >>   ASSERT (
> >>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE)
> ==
> >> 0 ||
> >>     PcdGetBool (PcdSetNxForStack)
> >>     );
> >>
> >
> > I don't have strong opinions on these. So let's do it your way.
> >
> >>>  +
> >>>  +  //
> >>>  +  // Image data section could be type of EfiLoaderData, 
> >>> EfiBootServicesData
> >>>  +  // or EfiRuntimeServicesData. Disabling NX for image data but 
> >>> enabling NX
> >>>  +  // for any those memory types doesn't make any sense.
> >>>  +  //
> >>
> >> The comment is good, I just suggest extending it with the origin of 
> >> the
> >> image: "Disabling NX for image data (regardless of image origin) 
> >> for any those memory types ...".
> >>
> >
> > Sure. I'll add it.
> >
> >>>  +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> >>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
> >>> IMAGE_DATA_MEM
> OR
> >> Y_TYPE) != 0) {
> >>>  +    DEBUG ((DEBUG_ERROR,
> >>>  +            "ERROR: NX for image data is disabled but NX for its 
> >>> memory type(s) is
> >> enabled!\r\n"));
> >>>  +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> >>>  +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & 
> >>> IMAGE_DATA_ME
> >> MORY_TYPE) != 0));
> >>>  +  }
> >>
> >> Summarizing my points from before, here we should have:
> >>
> >>   ASSERT (
> >>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMORY
> _TY
> >> PE) == 0 ||
> >>     PcdGet32 (PcdImageProtectionPolicy) == 3
> >>     );
> >>
> >> That is,
> >>
> >> - If we disable DxeNxMemoryProtectionPolicy for all of 
> >> EfiLoaderData,
> >>   EfiBootServicesData, and EfiRuntimeServicesData, then any
> >>   ImageProtectionPolicy is fine.
> >>
> >> - If we enable  DxeNxMemoryProtectionPolicy for any of 
> >> EfiLoaderData,
> >>   EfiBootServicesData, and EfiRuntimeServicesData, then we require 
> >> the
> >>   platform to set ImageProtectionPolicy regardless of image origin.
> >>
> >> Thanks
> >> Laszlo
> >>
> >
> > Good catch. I missed that part. Thanks.
> >
> >>>  +
> >>>  +  //
> >>>  +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
> >>>  +  // Features controlled by Following PCDs need this feature to be enabled.
> >>>  +  //
> >>>  +  return (PcdGetBool (PcdSetNxForStack) ||
> >>>  +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> >>>  +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> >>>  +}
> >>>  +
> >>>   /**
> >>>     Enable Execute Disable Bit.
> >>>
> >>>  @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
> >>>     //
> >>>     EnablePageTableProtection ((UINTN)PageMap, TRUE);
> >>>
> >>>  -  if (PcdGetBool (PcdSetNxForStack)) {
> >>>  +  //
> >>>  +  // Set IA32_EFER.NXE if necessary.
> >>>  +  //
> >>>  +  if (ToEnableExecuteDisableFeature ()) {
> >>>       EnableExecuteDisableBit ();
> >>>     }
> >>>
> >>>  diff --
> >>
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg
> >> /Core/DxeIplPeim/X64/VirtualMemory.h
> >>>  index 85457ff937..9f152e6531 100644
> >>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> >>>  @@ -179,6 +179,39 @@ typedef struct {
> >>>     UINTN           FreePages;
> >>>   } PAGE_TABLE_POOL;
> >>>
> >>>  +//
> >>>  +// Bit field repsentations of some EFI_MEMORY_TYPE, for page 
> >>> table initializ
> >> ation.
> >>>  +//
> >>>  +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)
> >>> /* 0x10 */
> >>>  +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)       
> >>> |
> >>> /* 0x04
> >> */\
> >>>  +                                     (1 << EfiBootServicesData) 
> >>> |
> >>> /* 0x10 */\
> >>>  +                                     (1 <<
> >>> EfiRuntimeServicesData)/* 0x40 */\
> >>>  +                                    )
> >>> /* 0x54 */
> >>>  +
> >>>  +/**
> >>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> >>>  +
> >>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
> >>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> >>>  +
> >>>  +**/
> >>>  +BOOLEAN
> >>>  +ToEnableExecuteDisableFeature (
> >>>  +  VOID
> >>>  +  );
> >>>  +
> >>>  +/**
> >>>  +  The function will check if Execute Disable Bit is available.
> >>>  +
> >>>  +  @retval TRUE      Execute Disable Bit is available.
> >>>  +  @retval FALSE     Execute Disable Bit is not available.
> >>>  +
> >>>  +**/
> >>>  +BOOLEAN
> >>>  +IsExecuteDisableBitAvailable (
> >>>  +  VOID
> >>>  +  );
> >>>  +
> >>>   /**
> >>>     Enable Execute Disable Bit.
> >>>
> >>>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-18  8:46           ` Zeng, Star
@ 2018-09-19  9:13             ` Wang, Jian J
  2018-09-19 11:39               ` Laszlo Ersek
  0 siblings, 1 reply; 14+ messages in thread
From: Wang, Jian J @ 2018-09-19  9:13 UTC (permalink / raw)
  To: Zeng, Star, Laszlo Ersek, edk2-devel@lists.01.org
  Cc: Ard Biesheuvel, Ni, Ruiyu, Yao, Jiewen

If no more new comments, I'll do following changes in v2, including review
comments got so far:

a. change ToEnableExecuteDisableFeature() to EnableNonExec()
b. remove the ASSERT and DEBUG in current ToEnableExecuteDisableFeature()
c. update dec/uni file to clarify the usage of following PCDs
    PcdNxSetForStack
        TRUE  - Apply NX to stack memory
        FALSE - Don't care of protection of stack memory
    PcdImageProtectionPolicy
         1 - Apply NX to data section of image from the corresponding origin
         0 - Don't care of the protection of data section of image from the corresponding origin
    PcdDxeNxMemoryProtectionPolicy
         1 - Apply NX to corresponding type of memory
         0 - Don't care of the protection of corresponding type of memory

Regards,
Jian


> -----Original Message-----
> From: Zeng, Star
> Sent: Tuesday, September 18, 2018 4:47 PM
> To: Wang, Jian J <jian.j.wang@intel.com>; Laszlo Ersek <lersek@redhat.com>;
> edk2-devel@lists.01.org
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> Yao, Jiewen <jiewen.yao@intel.com>; Zeng, Star <star.zeng@intel.com>
> Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> I totally agree adding more clear documentation in dec and uni.
> My only concern is that the warning message (by checking the combinations) to
> explain in c may bring more confusion.
> Anyway, if we can have the warning message to make the things more clear, I
> definitely agree it. :)
> 
> 
> Thanks,
> Star
> -----Original Message-----
> From: Wang, Jian J
> Sent: Tuesday, September 18, 2018 9:22 AM
> To: Laszlo Ersek <lersek@redhat.com>; Zeng, Star <star.zeng@intel.com>; edk2-
> devel@lists.01.org
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>;
> Yao, Jiewen <jiewen.yao@intel.com>
> Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> 
> I have no strong opinion for this proposal. But if we decide to do it finally, I'd
> suggest to add some warning messages for any probably surprising setting
> combinations.
> 
> Regards,
> Jian
> 
> 
> > -----Original Message-----
> > From: Laszlo Ersek [mailto:lersek@redhat.com]
> > Sent: Monday, September 17, 2018 6:14 PM
> > To: Zeng, Star <star.zeng@intel.com>; Wang, Jian J
> > <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>; Ni, Ruiyu
> > <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
> >
> > On 09/17/18 07:57, Zeng, Star wrote:
> > > How about we see the problem in another way?
> > >
> > > If my understanding is correct, current discussion and patches think
> > > FALSE/0
> > means disable/clear NX, but that is not the fact.
> > > According to the code implementation, FALSE/0 seems mean *AS IS* to
> > > do
> > thing (no code to disable/clear NX).
> > >
> > > PcdSetNxForStack
> > > TRUE: Set NX for stack.
> > > FALSE: No code to clear NX for stack.
> > >
> > > PcdDxeNxMemoryProtectionPolicy
> > > BITX 1: Set NX for that memory type.
> > > BITX 0: No code to clear NX for that memory type.
> > >
> > > PcdImageProtectionPolicy
> > > BITX 1: Set NX for the image data section.
> > > BITX 0: Not code to clear NX for the image data section.
> > >
> > > So, how about we think one PCD just works for itself and it does not
> > > impact
> > other PCDs to protect?
> > > That means TRUE/1 is to protect and FALSE/0 is *AS IS* to do nothing.
> > > The description of these PCDs could be enhancement if we think it is
> > > a good
> > way to see the problem.
> >
> > Sure, that too could work for me, but then the documentation in the
> > DEC / UNI files has to be really clear.
> >
> > The initial worry for the current discussion was that some platform
> > might
> > - protect e.g. BootServicesData type memory,
> > - not set PcdSetNxForStack,
> > - expect the stack to remain executable.
> >
> > The actual results might surprise the platform owner.
> >
> > If the documentation dispelled any possible misconceptions, I think
> > your idea could work too (and it would be a lot easier to code).
> >
> > Thanks
> > Laszlo
> >
> >
> > >
> > >
> > > Thanks,
> > > Star
> > > -----Original Message-----
> > > From: Wang, Jian J
> > > Sent: Monday, September 17, 2018 10:11 AM
> > > To: Laszlo Ersek <lersek@redhat.com>; edk2-devel@lists.01.org
> > > Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel
> > <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao,
> > Jiewen <jiewen.yao@intel.com>
> > > Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related
> > > PCDs
> > >
> > > Laszlo,
> > >
> > > Thanks for the comments.
> > >
> > > Regards,
> > > Jian
> > >
> > >> -----Original Message-----
> > >> From: Laszlo Ersek [mailto:lersek@redhat.com]
> > >> Sent: Friday, September 14, 2018 5:51 PM
> > >> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> > >> Cc: Zeng, Star <star.zeng@intel.com>; Ard Biesheuvel
> > >> <ard.biesheuvel@linaro.org>; Ni, Ruiyu <ruiyu.ni@intel.com>; Yao,
> > >> Jiewen <jiewen.yao@intel.com>
> > >> Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related
> > >> PCDs
> > >>
> > >> I've got some comments on the code as well:
> > >>
> > >> On 09/14/18 07:13, Jian J Wang wrote:
> > >>>  BZ#1116: https://bugzilla.tianocore.org/show_bug.cgi?id=1116
> > >>>
> > >>>  Currently IA32_EFER.NXE is only set against PcdSetNxForStack.
> > >>> This
> > >>>  confuses developers because following two other PCDs also need
> > >>> NXE
> > >>>  to be set, but actually not.
> > >>>
> > >>>      PcdDxeNxMemoryProtectionPolicy
> > >>>      PcdImageProtectionPolicy
> > >>>
> > >>>  This patch solves this issue by adding logic to enable
> > >>> IA32_EFER.NXE
> > >>>  if any of those PCDs have anything enabled.
> > >>>
> > >>>  Due to the fact that NX memory type of stack (enabled by
> > >>> PcdSetNxForStack)
> > >>>  and image data section (enabled by PcdImageProtectionPolicy) are
> > >>> also
> > >>>  part of PcdDxeNxMemoryProtectionPolicy, this patch also add more
> > >>> checks
> > >>>  to warn (ASSERT) users any unreasonable setting combinations. For
> > >>> example,
> > >>>
> > >>>      PcdSetNxForStack == FALSE &&
> > >>>        (PcdDxeNxMemoryProtectionPolicy & (1
> > >>> <<EfiBootServicesData)) != 0
> > >>>
> > >>>      PcdImageProtectionPolicy == 0 &&
> > >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<
> > >>> EfiRuntimeServicesData)) != 0
> > >>>
> > >>>      PcdImageProtectionPolicy == 0 &&
> > >>>        (PcdDxeNxMemoryProtectionPolicy & (1
> > >>> <<EfiBootServicesData)) != 0
> > >>>
> > >>>      PcdImageProtectionPolicy == 0 &&
> > >>>        (PcdDxeNxMemoryProtectionPolicy & (1 <<EfiLoaderData)) != 0
> > >>>
> > >>>  In other words, PcdSetNxForStack and PcdImageProtectionPolicy
> > >>> have
> > >>>  priority over PcdDxeNxMemoryProtectionPolicy.
> > >>>
> > >>>  Cc: Star Zeng <star.zeng@intel.com>
> > >>>  Cc: Laszlo Ersek <lersek@redhat.com>
> > >>>  Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > >>>  Cc: Ruiyu Ni <ruiyu.ni@intel.com>
> > >>>  Cc: Jiewen Yao <jiewen.yao@intel.com>
> > >>>  Contributed-under: TianoCore Contribution Agreement 1.1
> > >>>  Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> > >>>  ---
> > >>>   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          |  2 +
> > >>>   MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c  |  4 +-
> > >>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 55
> > >>> +++++++++++
> > ++
> > >> ++++++++++-
> > >>>   MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h | 33
> > >>> +++++++++++
> > ++
> > >> +
> > >>>   4 files changed, 91 insertions(+), 3 deletions(-)
> > >>>
> > >>>  diff --
> > >> git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> > >> b/MdeModulePkg/Core/DxeIp lPeim/DxeIpl.inf
> > >>>  index fd82657404..068e700074 100644
> > >>>  --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> > >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
> > >>>  @@ -117,6 +117,8 @@
> > >>>
> > >>>   [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
> > >>>     gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack
> > >>> ## SOMETIM
> > >> ES_CONSUMES
> > >>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolic
> y
> > ##
> > >> SOMETIMES_CONSUMES
> > >>>  +  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy
> > >>> ## SOME
> > >> TIMES_CONSUMES
> > >>>
> > >>>   [Depex]
> > >>>     gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
> > >>>  diff --
> > >>
> >
> git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/
> > >> Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > >>>  index d28baa3615..9a97205ef8 100644
> > >>>  --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
> > >>>  @@ -245,7 +245,7 @@ ToBuildPageTable (
> > >>>       return TRUE;
> > >>>     }
> > >>>
> > >>>  -  if (PcdGetBool (PcdSetNxForStack) &&
> > >>> IsExecuteDisableBitAvailable
> > >>> ()) {
> > >>>  +  if (ToEnableExecuteDisableFeature ()) {
> > >>>       return TRUE;
> > >>>     }
> > >>>
> > >>>  @@ -436,7 +436,7 @@ HandOffToDxeCore (
> > >>>       BuildPageTablesIa32Pae = ToBuildPageTable ();
> > >>>       if (BuildPageTablesIa32Pae) {
> > >>>         PageTables = Create4GPageTablesIa32Pae (BaseOfStack,
> > >>> STACK_SIZE);
> > >>>  -      if (IsExecuteDisableBitAvailable ()) {
> > >>>  +      if (ToEnableExecuteDisableFeature ()) {
> > >>>           EnableExecuteDisableBit();
> > >>>         }
> > >>>       }
> > >>>  diff --
> > >>
> >
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg
> > >> /Core/DxeIplPeim/X64/VirtualMemory.c
> > >>>  index 496e219913..253fe84223 100644
> > >>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> > >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> > >>>  @@ -106,6 +106,56 @@ IsNullDetectionEnabled (
> > >>>     return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0)
> > >>> != 0);
> > >>>   }
> > >>>
> > >>>  +/**
> > >>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> > >>>  +
> > >>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
> > >>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> > >>>  +
> > >>>  +**/
> > >>>  +BOOLEAN
> > >>>  +ToEnableExecuteDisableFeature (
> > >>>  +  VOID
> > >>>  +  )
> > >>
> > >> I think we're over-complicating the name of this function. First, "To"
> > >> looks unnecessary. Second, "Enable Execute Disable" is just an
> > >> engineer's way to say "Disable Execution". Can we say right that:
> > >> DisableExec()?
> > >>
> > >> Or at least, if we consider "NX" a word in its own right, "EnableNX()"?
> > >
> > > I prefer more general one. Let's use DisableExec().
> > >
> > >>
> > >>>  +{
> > >>>  +  if (!IsExecuteDisableBitAvailable ()) {
> > >>>  +    return FALSE;
> > >>>  +  }
> > >>>  +
> > >>>  +  //
> > >>>  +  // Normally stack is type of EfiBootServicesData. Disabling NX
> > >>> for stack
> > >>>  +  // but enabling NX for EfiBootServicesData doesn't make any sense.
> > >>>  +  //
> > >>
> > >> This comment is good.
> > >>
> > >>>  +  if (PcdGetBool (PcdSetNxForStack) == FALSE &&
> > >>
> > >> Please don't compare PcdGetBool() against TRUE or FALSE, just say
> > >> PcdGetBool(), or !PcdGetBool().
> > >>
> > >>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> > >>> STACK_MEMORY_TYPE)
> > >>  != 0) {
> > >>>  +    DEBUG ((DEBUG_ERROR,
> > >>>  +            "ERROR: NX for stack is disabled but NX for its
> > >>> memory type is enabled
> > >> !\r\n"));
> > >>>  +    ASSERT(!(PcdGetBool (PcdSetNxForStack) == FALSE &&
> > >>>  +             (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> > >>> STACK_MEMORY_T
> > >> YPE) != 0));
> > >>>  +  }
> > >>
> > >> Please drop both the explicit "if", and the DEBUG message. Just
> > >> keep the comment (which is already fine) and the ASSERT(). The
> > >> ASSERT() will tell people where to look, and the comment will
> > >> explain the assertion. Also, in a RELEASE build, the check should
> > >> be eliminated entirely, but that might not work for the explicit
> > >> "if" (dependent on compilers and/or fixed vs. dynamic PCDs).
> > >>
> > >> Furthermore, keeping the logical negation operator as the outermost
> > >> operator makes the code a lot harder to read. It's much better to
> > >> just assert what we actually require, which is:
> > >>
> > >>   (DxeNxMemoryProtectionPolicy covers BSD) --> SetNxForStack
> > >>
> > >> put differently,
> > >>
> > >>   NOT(DxeNxMemoryProtectionPolicy covers BSD) OR SetNxForStack
> > >>
> > >> in C:
> > >>
> > >>   ASSERT (
> > >>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & STACK_MEMORY_TYPE)
> > ==
> > >> 0 ||
> > >>     PcdGetBool (PcdSetNxForStack)
> > >>     );
> > >>
> > >
> > > I don't have strong opinions on these. So let's do it your way.
> > >
> > >>>  +
> > >>>  +  //
> > >>>  +  // Image data section could be type of EfiLoaderData,
> > >>> EfiBootServicesData
> > >>>  +  // or EfiRuntimeServicesData. Disabling NX for image data but
> > >>> enabling NX
> > >>>  +  // for any those memory types doesn't make any sense.
> > >>>  +  //
> > >>
> > >> The comment is good, I just suggest extending it with the origin of
> > >> the
> > >> image: "Disabling NX for image data (regardless of image origin)
> > >> for any those memory types ...".
> > >>
> > >
> > > Sure. I'll add it.
> > >
> > >>>  +  if (PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> > >>>  +      (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> > >>> IMAGE_DATA_MEM
> > OR
> > >> Y_TYPE) != 0) {
> > >>>  +    DEBUG ((DEBUG_ERROR,
> > >>>  +            "ERROR: NX for image data is disabled but NX for its
> > >>> memory type(s) is
> > >> enabled!\r\n"));
> > >>>  +    ASSERT (!(PcdGet32 (PcdImageProtectionPolicy) == 0 &&
> > >>>  +              (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &
> > >>> IMAGE_DATA_ME
> > >> MORY_TYPE) != 0));
> > >>>  +  }
> > >>
> > >> Summarizing my points from before, here we should have:
> > >>
> > >>   ASSERT (
> > >>     (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & IMAGE_DATA_MEMOR
> Y
> > _TY
> > >> PE) == 0 ||
> > >>     PcdGet32 (PcdImageProtectionPolicy) == 3
> > >>     );
> > >>
> > >> That is,
> > >>
> > >> - If we disable DxeNxMemoryProtectionPolicy for all of
> > >> EfiLoaderData,
> > >>   EfiBootServicesData, and EfiRuntimeServicesData, then any
> > >>   ImageProtectionPolicy is fine.
> > >>
> > >> - If we enable  DxeNxMemoryProtectionPolicy for any of
> > >> EfiLoaderData,
> > >>   EfiBootServicesData, and EfiRuntimeServicesData, then we require
> > >> the
> > >>   platform to set ImageProtectionPolicy regardless of image origin.
> > >>
> > >> Thanks
> > >> Laszlo
> > >>
> > >
> > > Good catch. I missed that part. Thanks.
> > >
> > >>>  +
> > >>>  +  //
> > >>>  +  // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is se
> t.
> > >>>  +  // Features controlled by Following PCDs need this feature to be enable
> d.
> > >>>  +  //
> > >>>  +  return (PcdGetBool (PcdSetNxForStack) ||
> > >>>  +          PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0 ||
> > >>>  +          PcdGet32 (PcdImageProtectionPolicy) != 0);
> > >>>  +}
> > >>>  +
> > >>>   /**
> > >>>     Enable Execute Disable Bit.
> > >>>
> > >>>  @@ -755,7 +805,10 @@ CreateIdentityMappingPageTables (
> > >>>     //
> > >>>     EnablePageTableProtection ((UINTN)PageMap, TRUE);
> > >>>
> > >>>  -  if (PcdGetBool (PcdSetNxForStack)) {
> > >>>  +  //
> > >>>  +  // Set IA32_EFER.NXE if necessary.
> > >>>  +  //
> > >>>  +  if (ToEnableExecuteDisableFeature ()) {
> > >>>       EnableExecuteDisableBit ();
> > >>>     }
> > >>>
> > >>>  diff --
> > >>
> >
> git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg
> > >> /Core/DxeIplPeim/X64/VirtualMemory.h
> > >>>  index 85457ff937..9f152e6531 100644
> > >>>  --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> > >>>  +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
> > >>>  @@ -179,6 +179,39 @@ typedef struct {
> > >>>     UINTN           FreePages;
> > >>>   } PAGE_TABLE_POOL;
> > >>>
> > >>>  +//
> > >>>  +// Bit field repsentations of some EFI_MEMORY_TYPE, for page
> > >>> table initializ
> > >> ation.
> > >>>  +//
> > >>>  +#define STACK_MEMORY_TYPE           (1 << EfiBootServicesData)
> > >>> /* 0x10 */
> > >>>  +#define IMAGE_DATA_MEMORY_TYPE      ((1 << EfiLoaderData)
> > >>> |
> > >>> /* 0x04
> > >> */\
> > >>>  +                                     (1 << EfiBootServicesData)
> > >>> |
> > >>> /* 0x10 */\
> > >>>  +                                     (1 <<
> > >>> EfiRuntimeServicesData)/* 0x40 */\
> > >>>  +                                    )
> > >>> /* 0x54 */
> > >>>  +
> > >>>  +/**
> > >>>  +  Check if Execute Disable Bit (IA32_EFER.NXE) should be enabled or not.
> > >>>  +
> > >>>  +  @retval TRUE    IA32_EFER.NXE should be enabled.
> > >>>  +  @retval FALSE   IA32_EFER.NXE should not be enabled.
> > >>>  +
> > >>>  +**/
> > >>>  +BOOLEAN
> > >>>  +ToEnableExecuteDisableFeature (
> > >>>  +  VOID
> > >>>  +  );
> > >>>  +
> > >>>  +/**
> > >>>  +  The function will check if Execute Disable Bit is available.
> > >>>  +
> > >>>  +  @retval TRUE      Execute Disable Bit is available.
> > >>>  +  @retval FALSE     Execute Disable Bit is not available.
> > >>>  +
> > >>>  +**/
> > >>>  +BOOLEAN
> > >>>  +IsExecuteDisableBitAvailable (
> > >>>  +  VOID
> > >>>  +  );
> > >>>  +
> > >>>   /**
> > >>>     Enable Execute Disable Bit.
> > >>>
> > >>>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
  2018-09-19  9:13             ` Wang, Jian J
@ 2018-09-19 11:39               ` Laszlo Ersek
  0 siblings, 0 replies; 14+ messages in thread
From: Laszlo Ersek @ 2018-09-19 11:39 UTC (permalink / raw)
  To: Wang, Jian J, Zeng, Star, edk2-devel@lists.01.org
  Cc: Ard Biesheuvel, Ni, Ruiyu, Yao, Jiewen

On 09/19/18 11:13, Wang, Jian J wrote:
> If no more new comments, I'll do following changes in v2, including review
> comments got so far:
> 
> a. change ToEnableExecuteDisableFeature() to EnableNonExec()
> b. remove the ASSERT and DEBUG in current ToEnableExecuteDisableFeature()
> c. update dec/uni file to clarify the usage of following PCDs
>     PcdNxSetForStack
>         TRUE  - Apply NX to stack memory
>         FALSE - Don't care of protection of stack memory
>     PcdImageProtectionPolicy
>          1 - Apply NX to data section of image from the corresponding origin
>          0 - Don't care of the protection of data section of image from the corresponding origin
>     PcdDxeNxMemoryProtectionPolicy
>          1 - Apply NX to corresponding type of memory
>          0 - Don't care of the protection of corresponding type of memory

Good summary, and I think this is a workable approach as well. Defining
value 0 as "don't care" or "no-op", rather than "unset this feature",
eliminates contradictory configurations.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2018-09-19 11:39 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-09-14  5:13 [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs Jian J Wang
2018-09-14  5:46 ` Wang, Jian J
2018-09-14  6:04 ` Ard Biesheuvel
2018-09-14  6:50   ` Wang, Jian J
2018-09-14  9:27     ` Laszlo Ersek
2018-09-17  1:00       ` Wang, Jian J
2018-09-14  9:50 ` Laszlo Ersek
2018-09-17  2:11   ` Wang, Jian J
2018-09-17  5:57     ` Zeng, Star
2018-09-17 10:13       ` Laszlo Ersek
2018-09-18  1:21         ` Wang, Jian J
2018-09-18  8:46           ` Zeng, Star
2018-09-19  9:13             ` Wang, Jian J
2018-09-19 11:39               ` Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox