EmbeddedPkg: Add option to disable EFI Memory Attribute Protocol

Introduce a driver that allows users to disable the EFI Memory Attribute
protocol through an HII setup option, in order to work around a broken
version of rhboot's shim used in some distros (e.g. CentOS Stream 9)
which incorrectly invokes the protocol and results in a Synchronous
Exception.

Default is enabled, which can also be overridden at build time by
changing `gEmbeddedTokenSpaceGuid.PcdMemoryAttributeEnabledDefault`.

It is only applicable to ARM64 and there isn't any other technical
reason for disabling this security feature.

See:
- https://github.com/microsoft/mu_silicon_arm_tiano/issues/124
- https://edk2.groups.io/g/devel/topic/99631663
- https://github.com/tianocore/edk2/pull/5840

Signed-off-by: Mario Bălănică <mariobalanica02@gmail.com>
This commit is contained in:
Mario Bălănică 2024-06-30 15:59:32 +03:00 committed by mergify[bot]
parent 1bb9f47739
commit f9c373c838
8 changed files with 360 additions and 0 deletions

View File

@ -0,0 +1,197 @@
/** @file
Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/HiiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include "MemoryAttributeManagerDxe.h"
extern UINT8 MemoryAttributeManagerDxeHiiBin[];
extern UINT8 MemoryAttributeManagerDxeStrings[];
typedef struct {
VENDOR_DEVICE_PATH VendorDevicePath;
EFI_DEVICE_PATH_PROTOCOL End;
} HII_VENDOR_DEVICE_PATH;
STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = {
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{
(UINT8)(sizeof (VENDOR_DEVICE_PATH)),
(UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
}
},
MEMORY_ATTRIBUTE_MANAGER_FORMSET_GUID
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
(UINT8)(END_DEVICE_PATH_LENGTH),
(UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
}
}
};
/**
Installs HII page for user configuration.
@retval EFI_SUCCESS The operation completed successfully.
**/
STATIC
EFI_STATUS
EFIAPI
InstallHiiPages (
VOID
)
{
EFI_STATUS Status;
EFI_HII_HANDLE HiiHandle;
EFI_HANDLE DriverHandle;
DriverHandle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverHandle,
&gEfiDevicePathProtocolGuid,
&mVendorDevicePath,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
HiiHandle = HiiAddPackages (
&gMemoryAttributeManagerFormSetGuid,
DriverHandle,
MemoryAttributeManagerDxeStrings,
MemoryAttributeManagerDxeHiiBin,
NULL
);
if (HiiHandle == NULL) {
gBS->UninstallMultipleProtocolInterfaces (
DriverHandle,
&gEfiDevicePathProtocolGuid,
&mVendorDevicePath,
NULL
);
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
/**
This function uninstalls the EFI_MEMORY_ATTRIBUTE_PROTOCOL
from CpuDxe's handle.
**/
STATIC
VOID
UninstallEfiMemoryAttributeProtocol (
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);
if (EFI_ERROR (Status)) {
return;
}
Status = gBS->UninstallProtocolInterface (
Handle,
&gEfiMemoryAttributeProtocolGuid,
MemoryAttributeProtocol
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return;
}
DEBUG ((
DEBUG_INFO,
"EFI Memory Attribute Protocol disabled due to user/platform preference!\n"
));
}
/**
The entry point for MemoryAttributeManagerDxe driver.
@param[in] ImageHandle The image handle of the driver.
@param[in] SystemTable The system table.
@retval EFI_SUCCESS The operation completed successfully.
**/
EFI_STATUS
EFIAPI
MemoryAttributeManagerInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINTN Size;
MEMORY_ATTRIBUTE_MANAGER_VARSTORE_DATA Config;
Config.Enabled = PROTOCOL_ENABLED_DEFAULT;
Size = sizeof (MEMORY_ATTRIBUTE_MANAGER_VARSTORE_DATA);
Status = gRT->GetVariable (
MEMORY_ATTRIBUTE_MANAGER_DATA_VAR_NAME,
&gMemoryAttributeManagerFormSetGuid,
NULL,
&Size,
&Config
);
if (EFI_ERROR (Status)) {
Status = gRT->SetVariable (
MEMORY_ATTRIBUTE_MANAGER_DATA_VAR_NAME,
&gMemoryAttributeManagerFormSetGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
Size,
&Config
);
ASSERT_EFI_ERROR (Status);
}
if (!Config.Enabled) {
UninstallEfiMemoryAttributeProtocol ();
}
return InstallHiiPages ();
}

View File

@ -0,0 +1,22 @@
/** @file
Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef MEMORY_ATTRIBUTE_MANAGER_DXE_H_
#define MEMORY_ATTRIBUTE_MANAGER_DXE_H_
#include <Guid/MemoryAttributeManagerFormSet.h>
#define PROTOCOL_ENABLED_DEFAULT FixedPcdGetBool(PcdMemoryAttributeEnabledDefault)
#define MEMORY_ATTRIBUTE_MANAGER_DATA_VAR_NAME L"MemoryAttributeManagerData"
typedef struct {
BOOLEAN Enabled;
} MEMORY_ATTRIBUTE_MANAGER_VARSTORE_DATA;
#endif // __MEMORY_ATTRIBUTE_MANAGER_DXE_H__

View File

@ -0,0 +1,62 @@
## @file
# EFI Memory Attribute Protocol state manager
#
# This driver allows users to disable the EFI Memory Attribute protocol
# through an HII setup option, in order to work around a broken version
# of rhboot's shim used in some distros (e.g. CentOS Stream 9) which
# incorrectly invokes the protocol and results in a Synchronous Exception.
#
# It is only applicable to ARM64 and there isn't any other technical
# reason for disabling this security feature.
#
# See:
# - https://github.com/microsoft/mu_silicon_arm_tiano/issues/124
# - https://edk2.groups.io/g/devel/topic/99631663
# - https://github.com/tianocore/edk2/pull/5840
#
# Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 0x0001001B
BASE_NAME = MemoryAttributeManagerDxe
FILE_GUID = 5319346b-66ad-433a-9a91-f7fc286bc9a1
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = MemoryAttributeManagerInitialize
[Sources]
MemoryAttributeManagerDxe.c
MemoryAttributeManagerDxe.h
MemoryAttributeManagerDxeHii.uni
MemoryAttributeManagerDxeHii.vfr
[Packages]
EmbeddedPkg/EmbeddedPkg.dec
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
DebugLib
DevicePathLib
HiiLib
UefiBootServicesTableLib
UefiRuntimeServicesTableLib
UefiDriverEntryPoint
[Guids]
gMemoryAttributeManagerFormSetGuid
[Protocols]
gEfiMemoryAttributeProtocolGuid
[Pcd]
gEmbeddedTokenSpaceGuid.PcdMemoryAttributeEnabledDefault
[Depex]
gEfiVariableArchProtocolGuid AND
gEfiVariableWriteArchProtocolGuid AND
gEfiMemoryAttributeProtocolGuid

View File

@ -0,0 +1,17 @@
/** @file
Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#langdef en-US "English"
#string STR_NULL_STRING #language en-US ""
#string STR_FORM_SET_TITLE #language en-US "EFI Memory Attribute Protocol"
#string STR_FORM_SET_TITLE_HELP #language en-US "Configure the state of the EFI Memory Attribute Protocol.\n\n"
"Some old OS loader versions (e.g. as found in CentOS Stream 9) do not properly support the protocol and may cause a Synchronous Exception. This security feature can be disabled to work around the issue; otherwise it should be kept enabled."
#string STR_ENABLE_PROTOCOL_PROMPT #language en-US "Enable Protocol"

View File

@ -0,0 +1,35 @@
/** @file
Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi/UefiMultiPhase.h>
#include <Guid/HiiPlatformSetupFormset.h>
#include "MemoryAttributeManagerDxe.h"
formset
guid = MEMORY_ATTRIBUTE_MANAGER_FORMSET_GUID,
title = STRING_TOKEN(STR_FORM_SET_TITLE),
help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
efivarstore MEMORY_ATTRIBUTE_MANAGER_VARSTORE_DATA,
attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
name = MemoryAttributeManagerData,
guid = MEMORY_ATTRIBUTE_MANAGER_FORMSET_GUID;
form formid = 1,
title = STRING_TOKEN(STR_FORM_SET_TITLE);
checkbox varid = MemoryAttributeManagerData.Enabled,
prompt = STRING_TOKEN(STR_ENABLE_PROTOCOL_PROMPT),
help = STRING_TOKEN(STR_NULL_STRING),
flags = CHECKBOX_DEFAULT | CHECKBOX_DEFAULT_MFG | RESET_REQUIRED,
default = PROTOCOL_ENABLED_DEFAULT,
endcheckbox;
endform;
endformset;

View File

@ -73,6 +73,9 @@
## Include/Guid/NvVarStoreFormatted.h
gEdkiiNvVarStoreFormattedGuid = { 0xd1a86e3f, 0x0707, 0x4c35, { 0x83, 0xcd, 0xdc, 0x2c, 0x29, 0xc8, 0x91, 0xa3 } }
# Include/Guid/MemoryAttributeManagerFormSet.h
gMemoryAttributeManagerFormSetGuid = { 0xefab3427, 0x4793, 0x4e9e, { 0xaa, 0x29, 0x88, 0x0c, 0x9a, 0x77, 0x5b, 0x5f } }
[Protocols.common]
gHardwareInterruptProtocolGuid = { 0x2890B3EA, 0x053D, 0x1643, { 0xAD, 0x0C, 0xD6, 0x48, 0x08, 0xDA, 0x3F, 0xF1 } }
gHardwareInterrupt2ProtocolGuid = { 0x32898322, 0x2da1, 0x474a, { 0xba, 0xaa, 0xf3, 0xf7, 0xcf, 0x56, 0x94, 0x70 } }
@ -192,3 +195,8 @@
# Expected Overflow Android Kernel Command Line Characters
#
gEmbeddedTokenSpaceGuid.PcdAndroidKernelCommandLineOverflow|0|UINT32|0x000005C
#
# EFI Memory Attribute Protocol default enable state
#
gEmbeddedTokenSpaceGuid.PcdMemoryAttributeEnabledDefault|TRUE|BOOLEAN|0x00000060

View File

@ -239,6 +239,8 @@
EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf
EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf
EmbeddedPkg/Drivers/MemoryAttributeManagerDxe/MemoryAttributeManagerDxe.inf
EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf {
<LibraryClasses>
DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf

View File

@ -0,0 +1,17 @@
/** @file
Copyright (c) 2023-2024, Mario Bălănică <mariobalanica02@gmail.com>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef MEMORY_ATTRIBUTE_MANAGER_FORMSET_H_
#define MEMORY_ATTRIBUTE_MANAGER_FORMSET_H_
#define MEMORY_ATTRIBUTE_MANAGER_FORMSET_GUID \
{ 0xefab3427, 0x4793, 0x4e9e, { 0xaa, 0x29, 0x88, 0x0c, 0x9a, 0x77, 0x5b, 0x5f } }
extern EFI_GUID gMemoryAttributeManagerFormSetGuid;
#endif // __MEMORY_ATTRIBUTE_MANAGER_FORMSET_H__