Skip to content

Commit

Permalink
ArmVirtQemu: Allow EFI memory attributes protocol to be disabled
Browse files Browse the repository at this point in the history
Shim's PE loader uses the EFI memory attributes protocol in a way that
results in an immediate crash when invoking the loaded image, unless the
base and size of its executable segment are both aligned to 4k.

If this is not the case, it will strip the memory allocation of its
executable permissions, but fail to add them back for the executable
region, resulting in non-executable code. Unfortunately, the PE loader
does not even bother invoking the protocol in this case (as it notices
the misalignment), making it very hard for system firmware to work
around this by attempting to infer the intent of the caller.

So let's introduce a QEMU command line option to indicate that the
protocol should not be exposed at all, and a PCD to set the default for
this option when it is omitted.

Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Link: https://gitlab.com/qemu-project/qemu/-/issues/1990
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
  • Loading branch information
ardbiesheuvel authored and mergify[bot] committed Dec 12, 2023
1 parent 725acd0 commit cee7ba3
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
6 changes: 6 additions & 0 deletions ArmVirtPkg/ArmVirtPkg.dec
Expand Up @@ -68,3 +68,9 @@
# Cloud Hypervisor has no other way to pass Rsdp address to the guest except use a PCD.
#
gArmVirtTokenSpaceGuid.PcdCloudHvAcpiRsdpBaseAddress|0x0|UINT64|0x00000005

##
# Whether the EFI memory attributes protocol should be uninstalled before
# invoking the OS loader. This may be needed to work around problematic
# builds of shim that use the protocol incorrectly.
gArmVirtTokenSpaceGuid.PcdUninstallMemAttrProtocol|FALSE|BOOLEAN|0x00000006
64 changes: 64 additions & 0 deletions ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
Expand Up @@ -16,6 +16,7 @@
#include <Library/PcdLib.h>
#include <Library/PlatformBmPrintScLib.h>
#include <Library/QemuBootOrderLib.h>
#include <Library/QemuFwCfgSimpleParserLib.h>
#include <Library/TpmPlatformHierarchyLib.h>
#include <Library/UefiBootManagerLib.h>
#include <Protocol/DevicePath.h>
Expand Down Expand Up @@ -1111,6 +1112,49 @@ PlatformBootManagerBeforeConsole (
FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciSerial, SetupVirtioSerial);
}

/**
Uninstall the EFI memory attribute protocol if it exists.
**/
STATIC
VOID
UninstallEfiMemoryAttributesProtocol (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
UINTN Size;
VOID *MemoryAttributeProtocol;

Size = sizeof (Handle);
Status = gBS->LocateHandle (
ByProtocol,
&gEfiMemoryAttributeProtocolGuid,
NULL,
&Size,
&Handle
);

if (EFI_ERROR (Status)) {
ASSERT (Status == EFI_NOT_FOUND);
return;
}

Status = gBS->HandleProtocol (
Handle,
&gEfiMemoryAttributeProtocolGuid,
&MemoryAttributeProtocol
);
ASSERT_EFI_ERROR (Status);

Status = gBS->UninstallProtocolInterface (
Handle,
&gEfiMemoryAttributeProtocolGuid,
MemoryAttributeProtocol
);
ASSERT_EFI_ERROR (Status);
}

/**
Do the platform specific action after the console is ready
Possible things that can be done in PlatformBootManagerAfterConsole:
Expand All @@ -1129,12 +1173,32 @@ PlatformBootManagerAfterConsole (
)
{
RETURN_STATUS Status;
BOOLEAN Uninstall;

//
// Show the splash screen.
//
BootLogoEnableLogo ();

//
// Work around shim's terminally broken use of the EFI memory attributes
// protocol, by uninstalling it if requested on the QEMU command line.
//
// E.g.,
// -fw_cfg opt/org.tianocore/UninstallMemAttrProtocol,string=y
//
Uninstall = FixedPcdGetBool (PcdUninstallMemAttrProtocol);
QemuFwCfgParseBool ("opt/org.tianocore/UninstallMemAttrProtocol", &Uninstall);
DEBUG ((
DEBUG_WARN,
"%a: %auninstalling EFI memory protocol\n",
__func__,
Uninstall ? "" : "not "
));
if (Uninstall) {
UninstallEfiMemoryAttributesProtocol ();
}

//
// Process QEMU's -kernel command line option. The kernel booted this way
// will receive ACPI tables: in PlatformBootManagerBeforeConsole(), we
Expand Down
Expand Up @@ -46,6 +46,7 @@
PcdLib
PlatformBmPrintScLib
QemuBootOrderLib
QemuFwCfgSimpleParserLib
QemuLoadImageLib
ReportStatusCodeLib
TpmPlatformHierarchyLib
Expand All @@ -55,6 +56,7 @@
UefiRuntimeServicesTableLib

[FixedPcd]
gArmVirtTokenSpaceGuid.PcdUninstallMemAttrProtocol
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
Expand All @@ -73,5 +75,6 @@
[Protocols]
gEfiFirmwareVolume2ProtocolGuid
gEfiGraphicsOutputProtocolGuid
gEfiMemoryAttributeProtocolGuid
gEfiPciRootBridgeIoProtocolGuid
gVirtioDeviceProtocolGuid

0 comments on commit cee7ba3

Please sign in to comment.