summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Jones <pjones@redhat.com>2021-12-02 15:51:00 -0500
committerPeter Jones <pjones@redhat.com>2022-05-17 19:01:03 -0400
commitb104fc480aae94eaa8d79717d0b7cf6dcc2253d3 (patch)
tree3976d11a6e02fe28d0f2a25498cd20ff99b8d47a
parentdf96f48f28fa94b62d06f39a3b014133dd38def5 (diff)
downloadefi-boot-shim-b104fc480aae94eaa8d79717d0b7cf6dcc2253d3.tar.gz
efi-boot-shim-b104fc480aae94eaa8d79717d0b7cf6dcc2253d3.zip
post-process-pe: set EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT
Currently, system firmware has no means to discover that an EFI Application is compatible with the security feature variously known as NX or w^x. Since at least Revision 8.1, the PE spec supports setting a flag the Optional Header's DllCharacteristics field to inform loaders that an application supports being loaded with NX enabled. In the case of UEFI, there are several things that should be enabled if this flag is set: - EFI_BOOT_SERVICES.AllocatePages() with MemoryType = EfiLoaderCode, EfiBootServicesCode, EfiRuntimeServicesCode, etc, currently must set memory as rwx. This flag set implies that rw- is appropriate, and that the application knows how to use the EFI_MEMORY_ATTRIBUTE protocol to change that to r-x. - EFI_BOOT_SERVICES.AllocatePool() - same as AllocatePages() - EFI_BOOT_SERVICES.LoadImage() - currently must set the stack as rwx. This flag states that it is allowed to be rw- - currently a binary can probably have writable PLTs? This flag allows the loader to not set them writable - I have heard that some firmwares have the 0 page mapped rwx. Obviously this should not be done. Signed-off-by: Peter Jones <pjones@redhat.com>
-rw-r--r--post-process-pe.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/post-process-pe.c b/post-process-pe.c
index e848f009..de8f4a38 100644
--- a/post-process-pe.c
+++ b/post-process-pe.c
@@ -11,6 +11,7 @@
#include <getopt.h>
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -41,6 +42,8 @@ static int verbosity;
0; \
})
+static bool set_nx_compat = false;
+
typedef uint8_t UINT8;
typedef uint16_t UINT16;
typedef uint32_t UINT32;
@@ -331,6 +334,33 @@ load_pe(const char *const file, void *const data, const size_t datasize,
}
static void
+set_dll_characteristics(PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
+{
+ uint16_t oldflags, newflags;
+
+ if (image_is_64_bit(ctx->PEHdr)) {
+ oldflags = ctx->PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics;
+ } else {
+ oldflags = ctx->PEHdr->Pe32.OptionalHeader.DllCharacteristics;
+ }
+
+ if (set_nx_compat)
+ newflags = oldflags | EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
+ else
+ newflags = oldflags & ~(uint16_t)EFI_IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
+ if (oldflags == newflags)
+ return;
+
+ debug(INFO, "Updating DLL Characteristics from 0x%04hx to 0x%04hx\n",
+ oldflags, newflags);
+ if (image_is_64_bit(ctx->PEHdr)) {
+ ctx->PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics = newflags;
+ } else {
+ ctx->PEHdr->Pe32.OptionalHeader.DllCharacteristics = newflags;
+ }
+}
+
+static void
fix_timestamp(PE_COFF_LOADER_IMAGE_CONTEXT *ctx)
{
uint32_t ts;
@@ -417,6 +447,8 @@ handle_one(char *f)
load_pe(f, map, sz, &ctx);
+ set_dll_characteristics(&ctx);
+
fix_timestamp(&ctx);
fix_checksum(&ctx, map, sz);
@@ -449,6 +481,8 @@ static void __attribute__((__noreturn__)) usage(int status)
fprintf(out, "Options:\n");
fprintf(out, " -q Be more quiet\n");
fprintf(out, " -v Be more verbose\n");
+ fprintf(out, " -N Disable the NX compatibility flag\n");
+ fprintf(out, " -n Enable the NX compatibility flag\n");
fprintf(out, " -h Print this help text and exit\n");
exit(status);
@@ -464,6 +498,12 @@ int main(int argc, char **argv)
{.name = "usage",
.val = '?',
},
+ {.name = "disable-nx-compat",
+ .val = 'N',
+ },
+ {.name = "enable-nx-compat",
+ .val = 'n',
+ },
{.name = "quiet",
.val = 'q',
},
@@ -474,12 +514,18 @@ int main(int argc, char **argv)
};
int longindex = -1;
- while ((i = getopt_long(argc, argv, "hqv", options, &longindex)) != -1) {
+ while ((i = getopt_long(argc, argv, "hNnqv", options, &longindex)) != -1) {
switch (i) {
case 'h':
case '?':
usage(longindex == -1 ? 1 : 0);
break;
+ case 'N':
+ set_nx_compat = false;
+ break;
+ case 'n':
+ set_nx_compat = true;
+ break;
case 'q':
verbosity = MAX(verbosity - 1, MIN_VERBOSITY);
break;