public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: Jian J Wang <jian.j.wang@intel.com>, edk2-devel@lists.01.org
Cc: Star Zeng <star.zeng@intel.com>,
	Ard Biesheuvel <ard.biesheuvel@linaro.org>,
	Ruiyu Ni <ruiyu.ni@intel.com>, Jiewen Yao <jiewen.yao@intel.com>
Subject: Re: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs
Date: Fri, 14 Sep 2018 11:50:57 +0200	[thread overview]
Message-ID: <9d5d297a-4d10-3ffd-3d02-1f369cfe5bda@redhat.com> (raw)
In-Reply-To: <20180914051335.2644-1-jian.j.wang@intel.com>

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.
>
>



  parent reply	other threads:[~2018-09-14  9:51 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9d5d297a-4d10-3ffd-3d02-1f369cfe5bda@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox