Skip to content

Commit

Permalink
BaseTools: GenFw: auto-set nxcompat flag
Browse files Browse the repository at this point in the history
Automatically set the nxcompat flag in the DLL Characteristics field of
the Optional Header of the PE32+ image. For this flag to be set
automatically, the section alignment must be evenly divisible
by 4K (EFI_PAGE_SIZE) and no section must be executable and writable.

Adds a command line flag to GenFw, --nonxcompat, to ensure the
IMAGE_DLLCHARACTERISTICS_NX_COMPAT bit is not set, even if all
requirements are met. Updates the manual for GenFw to include the new
flag.

Cc: Rebecca Cran <[email protected]>
Cc: Liming Gao <[email protected]>
Cc: Bob Feng <[email protected]>
Cc: Yuwei Chen <[email protected]>
Signed-off-by: Joey Vagedes <[email protected]>
Acked-by: Liming Gao <[email protected]>
Reviewed-by: Rebecca Cran <[email protected]>
  • Loading branch information
Javagedes authored and mergify[bot] committed Nov 6, 2023
1 parent e53c618 commit da21991
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 381 deletions.
69 changes: 69 additions & 0 deletions BaseTools/Source/C/GenFw/GenFw.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ UINT32 mImageSize = 0;
UINT32 mOutImageType = FW_DUMMY_IMAGE;
BOOLEAN mIsConvertXip = FALSE;
BOOLEAN mExportFlag = FALSE;
BOOLEAN mNoNxCompat = FALSE;

STATIC
EFI_STATUS
Expand Down Expand Up @@ -281,6 +282,9 @@ Routine Description:
write export table into PE-COFF.\n\
This option can be used together with -e.\n\
It doesn't work for other options.\n");
fprintf (stdout, " --nonxcompat Do not set the IMAGE_DLLCHARACTERISTICS_NX_COMPAT bit \n\
of the optional header in the PE header even if the \n\
requirements are met.\n");
fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n");
fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n");
fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n");
Expand Down Expand Up @@ -441,6 +445,59 @@ Routine Description:
return STATUS_SUCCESS;
}

/**
Checks if the Pe image is nxcompat compliant.
Must meet the following conditions:
1. The PE is 64bit
2. The section alignment is evenly divisible by 4k
3. No section is writable and executable.
@param PeHdr - The PE header
@retval TRUE - The PE is nx compat compliant
@retval FALSE - The PE is not nx compat compliant
**/
STATIC
BOOLEAN
IsNxCompatCompliant (
EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr
)
{
EFI_IMAGE_SECTION_HEADER *SectionHeader;
UINT32 Index;
UINT32 Mask;

// Must have an optional header to perform verification
if (PeHdr->Pe32.FileHeader.SizeOfOptionalHeader == 0) {
return FALSE;
}

// Verify PE is 64 bit
if (!(PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
return FALSE;
}

// Verify Section Alignment is divisible by 4K
if (!((PeHdr->Pe32Plus.OptionalHeader.SectionAlignment % EFI_PAGE_SIZE) == 0)) {
return FALSE;
}

// Verify sections are not Write & Execute
Mask = EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_WRITE;
SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32Plus.OptionalHeader) + PeHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader);
for (Index = 0; Index < PeHdr->Pe32Plus.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
if ((SectionHeader->Characteristics & Mask) == Mask) {
return FALSE;
}
}

// Passed all requirements, return TRUE
return TRUE;
}

VOID
SetHiiResourceHeader (
UINT8 *HiiBinData,
Expand Down Expand Up @@ -1452,6 +1509,13 @@ Routine Description:
continue;
}

if (stricmp (argv[0], "--nonxcompat") == 0) {
mNoNxCompat = TRUE;
argc --;
argv ++;
continue;
}

if (argv[0][0] == '-') {
Error (NULL, 0, 1000, "Unknown option", argv[0]);
goto Finish;
Expand Down Expand Up @@ -2458,6 +2522,11 @@ Routine Description:
TEImageHeader.BaseOfCode = Optional64->BaseOfCode;
TEImageHeader.ImageBase = (UINT64) (Optional64->ImageBase);

// Set NxCompat flag
if (IsNxCompatCompliant (PeHdr) && !mNoNxCompat) {
Optional64->DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
}

if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
Expand Down
Loading

0 comments on commit da21991

Please sign in to comment.