From 4ccfe5b477fd5acc92500d2284be169e58d6a8eb Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Tue, 10 Sep 2024 16:23:06 +0100 Subject: [PATCH] StandaloneMmPkg: Arm: Call TextUpdate after ReadwriteUpdater The StandaloneMm implementation for Arm sets up the stack in the early startup code using the data section reserved in the assembly code. When TF-A loads the StandaloneMM binary in the DRAM it maps the entire StandaloneMM memory region as Read Only. Therefore, the initial startup assembly code updates the mem permissions of the stack region to Read Write. However, when the StandaloneMmCore is loaded the function UpdateMmFoundationPeCoffPermissions() starts applying the memory permissions based on the PE COFF sections as below: A. If the section is not executable, it first removes the executable permission of the section by calling TextUpdate(). TextUpdate() is the StandaloneMM MMU library function ArmSetMemoryRegionNoExec(). B. It then checks if the section is writable, and if it is it calls ReadWriteUpdater(), which invokes the StandaloneMM MMU library function ArmClearMemoryRegionReadOnly() to make the section writable. However, this results in the stack being made read-only between A and B. To understand this please see the following flow. 1. TF-A sets the entire StandaloneMM region as Read Only. 2. The stack is reserved in the data section by the early assembly entry point code. +--------------------+ <--- Start of Data Section | | | Data Section | | | | +----------------+ | <--- Stack region | | Stack | | | +----------------+ | | | +--------------------+ 3. The StanaloneMM early entry point code updates the attributes of the stack to Read Write. 4. When UpdateMmFoundationPeCoffPermissions() sets the permission of the data section to remove the Execute attribute, it calls ArmSetMemoryRegionNoExec(). 5. The ArmSetMemoryRegionNoExec() implementation gets the attributes of the first granule which is at the start of the data section, then clears the execute permission and applies the attribute for the entire data section. 6. Since TF-A has mapped the entire section as read only the first granule of the data section is read only and therefore the stack region attributes are changed to Read Only no execute. 7. Since the stack is read only after point A any updates to the stack result in an exception. To resolve this issue, reverse the order of the PE COFF section permission initialisation (i.e. step A and B) so that the Read Write attribute is first set for the data section, and then the execute permission is removed. By doing this the write permission for the stack region is preserved. Signed-off-by: Levi Yun --- .../Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c index 5c6bd0e1d7d29..4011adec1ee61 100644 --- a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c +++ b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c @@ -126,8 +126,6 @@ UpdateMmFoundationPeCoffPermissions ( if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { Base = ImageBase + SectionHeader.VirtualAddress; - TextUpdater (Base, SectionHeader.Misc.VirtualSize); - if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) { ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize); DEBUG (( @@ -146,6 +144,8 @@ UpdateMmFoundationPeCoffPermissions ( ImageContext->ImageAddress )); } + + TextUpdater (Base, SectionHeader.Misc.VirtualSize); } else { DEBUG (( DEBUG_INFO,