On Thu, 7 Dec 2023 at 11:06, Ard Biesheuvel <a...@google.com> wrote:
>
> From: Ard Biesheuvel <a...@kernel.org>
>
> 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 on the first boot, which is when
> the issue is triggered. (fbaa64.efi is broken but grubaa64.efi boots
> fine)
>
>   -fw_cfg opt/org.tianocore/UninstallMemAttrProtocolOnFirstBoot,string=y
>
> Also introduce a fixed boolean PCD that sets the default.
>
> Cc: Laszlo Ersek <ler...@redhat.com>
> Cc: Gerd Hoffmann <kra...@redhat.com>
> Cc: Oliver Steffen <ostef...@redhat.com>
> Cc: Alexander Graf <g...@amazon.com>
> Cc: Oliver Smith-Denny <o...@linux.microsoft.com>
> Cc: Taylor Beebe <taylor.d.be...@gmail.com>
> Cc: Peter Jones <pjo...@redhat.com>
> Cc: Leif Lindholm <quic_llind...@quicinc.com>
> Link: https://gitlab.com/qemu-project/qemu/-/issues/1990
> Signed-off-by: Ard Biesheuvel <a...@kernel.org>

OK, if nobody has problems with this approach, I intend to merge it
and give a snapshot build to the lima folks to incorporate in their
scripts.


> ---
>  ArmVirtPkg/ArmVirtPkg.dec                                            |  6 ++
>  ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf |  7 ++
>  ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c               | 85 
> ++++++++++++++++++++
>  3 files changed, 98 insertions(+)
>
> diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec
> index 0f2d7873279f..c55978f75c19 100644
> --- a/ArmVirtPkg/ArmVirtPkg.dec
> +++ b/ArmVirtPkg/ArmVirtPkg.dec
> @@ -68,3 +68,9 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
>    # 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 attribus protocol should be uninstalled before
>
> +  # invoking the OS loader on the first boot. This may be needed to work 
> around
>
> +  # problematic builds of shim that use the protocol incorrectly.
>
> +  
> gArmVirtTokenSpaceGuid.PcdUninstallMemAttrProtocolOnFirstBoot|FALSE|BOOLEAN|0x00000006
>
> diff --git 
> a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf 
> b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> index 997eb1a4429f..5d119af6a3b3 100644
> --- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> +++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> @@ -16,6 +16,7 @@ [Defines]
>    MODULE_TYPE                    = DXE_DRIVER
>
>    VERSION_STRING                 = 1.0
>
>    LIBRARY_CLASS                  = PlatformBootManagerLib|DXE_DRIVER
>
> +  CONSTRUCTOR                    = PlatformBootManagerLibConstructor
>
>
>
>  #
>
>  # The following information is for reference only and not required by the 
> build tools.
>
> @@ -46,6 +47,7 @@ [LibraryClasses]
>    PcdLib
>
>    PlatformBmPrintScLib
>
>    QemuBootOrderLib
>
> +  QemuFwCfgSimpleParserLib
>
>    QemuLoadImageLib
>
>    ReportStatusCodeLib
>
>    TpmPlatformHierarchyLib
>
> @@ -55,6 +57,7 @@ [LibraryClasses]
>    UefiRuntimeServicesTableLib
>
>
>
>  [FixedPcd]
>
> +  gArmVirtTokenSpaceGuid.PcdUninstallMemAttrProtocolOnFirstBoot
>
>    gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
>
>    gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
>
>    gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
>
> @@ -73,5 +76,9 @@ [Guids]
>  [Protocols]
>
>    gEfiFirmwareVolume2ProtocolGuid
>
>    gEfiGraphicsOutputProtocolGuid
>
> +  gEfiMemoryAttributeProtocolGuid
>
>    gEfiPciRootBridgeIoProtocolGuid
>
>    gVirtioDeviceProtocolGuid
>
> +
>
> +[Depex]
>
> +  gEfiVariableArchProtocolGuid
>
> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c 
> b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
> index 85c01351b09d..5306d9ea0a05 100644
> --- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
> +++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
> @@ -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>
>
> @@ -1274,3 +1275,87 @@ PlatformBootManagerUnableToBoot (
>      EfiBootManagerBoot (&BootManagerMenu);
>
>    }
>
>  }
>
> +
>
> +/**
>
> +  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);
>
> +}
>
> +
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PlatformBootManagerLibConstructor (
>
> +  IN EFI_HANDLE        ImageHandle,
>
> +  IN EFI_SYSTEM_TABLE  *SystemTable
>
> +  )
>
> +{
>
> +  BOOLEAN  Uninstall;
>
> +  UINTN    VarSize;
>
> +  UINT32   Attr;
>
> +
>
> +  //
>
> +  // 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/UninstallMemAttrProtocolOnFirstBoot,string=y
>
> +  //
>
> +  // This is only needed on the first boot, when fbaa64.efi is being invoked 
> to
>
> +  // set the boot order variables. Subsequent boots involving GRUB are not
>
> +  // affected.
>
> +  //
>
> +  VarSize = 0;
>
> +  if (gRT->GetVariable (
>
> +             L"BootOrder",
>
> +             &gEfiGlobalVariableGuid,
>
> +             &Attr,
>
> +             &VarSize,
>
> +             NULL
>
> +             ) == EFI_NOT_FOUND)
>
> +  {
>
> +    Uninstall = FixedPcdGetBool (PcdUninstallMemAttrProtocolOnFirstBoot);
>
> +    QemuFwCfgParseBool 
> ("opt/org.tianocore/UninstallMemAttrProtocolOnFirstBoot", &Uninstall);
>
> +    if (Uninstall) {
>
> +      UninstallEfiMemoryAttributesProtocol ();
>
> +    }
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> --
> 2.43.0.rc2.451.g8631bc7472-goog
>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112225): https://edk2.groups.io/g/devel/message/112225
Mute This Topic: https://groups.io/mt/103031504/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to