]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ukify: drop NX bit from UKI if kernel doesn't have it
authorLuca Boccassi <luca.boccassi@gmail.com>
Tue, 12 Aug 2025 22:09:06 +0000 (23:09 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 13 Aug 2025 18:49:20 +0000 (03:49 +0900)
If the kernel is not NX_COMPAT ready (W^X memory compatible) then the
UKI should not be marked as NX_COMPAT ready either, as the kernel
section is the loadable code in the image.

https://microsoft.github.io/mu/WhatAndWhy/enhancedmemoryprotection/
https://www.kraxel.org/blog/2023/12/uefi-nx-linux-boot/

While the sd-stub EFI code itself is NX ready, it is more useful
to think of it as one unit of execution together with the kernel
it embeds, as that's what it is used for.

Fixes https://github.com/systemd/systemd/issues/38545

src/ukify/ukify.py

index 8a8d72429fe2f8a8dcf16b42aefdbf2340c18174..a09ea09f9ed9537beafcb90c963b9c1993418428 100755 (executable)
@@ -1023,6 +1023,19 @@ def pe_add_sections(opts: UkifyConfig, uki: UKI, output: str) -> None:
         if section.name == '.linux':
             # Old kernels that use EFI handover protocol will be executed inline.
             new_section.IMAGE_SCN_CNT_CODE = True
+
+            # Check if the kernel PE has the NX_COMPAT flag set, if not strip it from the UKI as they need
+            # to have the same value, otherwise when firmwares start enforcing it, booting will fail.
+            # https://microsoft.github.io/mu/WhatAndWhy/enhancedmemoryprotection/
+            # https://www.kraxel.org/blog/2023/12/uefi-nx-linux-boot/
+            try:
+                inner_pe = pefile.PE(data=data, fast_load=True)
+                nxbit = pefile.DLL_CHARACTERISTICS['IMAGE_DLLCHARACTERISTICS_NX_COMPAT']
+                if not inner_pe.OPTIONAL_HEADER.DllCharacteristics & nxbit:
+                    pe.OPTIONAL_HEADER.DllCharacteristics &= ~nxbit
+            except pefile.PEFormatError:
+                # Unit tests build images with bogus data
+                print(f'{section.name} in {uki.executable} is not a valid PE, ignoring', file=sys.stderr)
         else:
             new_section.IMAGE_SCN_CNT_INITIALIZED_DATA = True