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 <[email protected]>; [email protected] Cc: Zeng, Star <[email protected]>; Ard Biesheuvel <[email protected]>; Ni, Ruiyu <[email protected]>; Yao, Jiewen <[email protected]> Subject: RE: [PATCH] MdeModulePkg/DxeIpl: support more NX related PCDs Laszlo, Thanks for the comments. Regards, Jian > -----Original Message----- > From: Laszlo Ersek [mailto:[email protected]] > Sent: Friday, September 14, 2018 5:51 PM > To: Wang, Jian J <[email protected]>; [email protected] > Cc: Zeng, Star <[email protected]>; Ard Biesheuvel > <[email protected]>; Ni, Ruiyu <[email protected]>; Yao, > Jiewen <[email protected]> > 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 <[email protected]> > > Cc: Laszlo Ersek <[email protected]> > > Cc: Ard Biesheuvel <[email protected]> > > Cc: Ruiyu Ni <[email protected]> > > Cc: Jiewen Yao <[email protected]> > > Contributed-under: TianoCore Contribution Agreement 1.1 > > Signed-off-by: Jian J Wang <[email protected]> > > --- > > 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. > > > > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

