Skip to content

Commit 75770db

Browse files
apop5os-d
andauthored
UefiCpuPkg: Add Ro to Ap Buffer after copying ApLoopCode. (#1356)
## Description MpLib allocates a buffer for Ap Loop code. It manually removes the Nx protection but never applies any other protections to the buffer, leaving it RWX. After the code is copied into the allocated buffer, apply Read Only permissions so that nothing can overwrite it while the APs are executing from it. In the update to 202502, Edk2 modified their code layout, resulting in the AP buffer being allocated with Nx, having Nx removed, and then never applying any other memory protections. - [x] Impacts functionality? - [x] Impacts security? - [ ] Breaking change? - [ ] Includes tests? - [ ] Includes documentation? - [x] Backport to release branch? ## How This Was Tested Executing DxePagingAudit test application on Q35 found one region of memory marked RWX. Applying these modifications, DxePagingAudit test application no longer reports a RWX buffer. ## Integration Instructions No integration necessary. Signed-off-by: Aaron Pop <[email protected]> Co-authored-by: Oliver Smith-Denny <[email protected]>
1 parent b3b3644 commit 75770db

File tree

4 files changed

+91
-127
lines changed

4 files changed

+91
-127
lines changed

UefiCpuPkg/Library/MpInitLib/DxeMpLib.c

Lines changed: 63 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,12 @@ CPU_MP_DEBUG_PROTOCOL mCpuMpDebugProtocol = {
3939

4040
#define AP_SAFE_STACK_SIZE 128
4141

42-
CPU_MP_DATA *mCpuMpData = NULL;
43-
EFI_EVENT mCheckAllApsEvent = NULL;
44-
EFI_EVENT mMpInitExitBootServicesEvent = NULL;
45-
EFI_EVENT mLegacyBootEvent = NULL;
46-
volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
47-
// MU_CHANGE START: Enable removal of NX attribute from buffer
42+
CPU_MP_DATA *mCpuMpData = NULL;
43+
EFI_EVENT mCheckAllApsEvent = NULL;
44+
EFI_EVENT mMpInitExitBootServicesEvent = NULL;
45+
EFI_EVENT mLegacyBootEvent = NULL;
46+
volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
4847
extern RELOCATE_AP_LOOP_ENTRY mReservedApLoop;
49-
// MU_CHANGE END: Enable removal of NX attribute from buffer
5048

5149
//
5250
// Begin wakeup buffer allocation below 0x88000
@@ -110,57 +108,6 @@ InstallCpuMpDebugProtocol (
110108
DEBUG ((DEBUG_INFO, "Installed gCpuMpDebugProtocolGuid - Status: %r\n", Status));
111109
}
112110

113-
// MU_CHANGE START: Enable removal of NX attribute from buffer
114-
115-
/**
116-
Remove NX attribute from Buffer and apply RO to Buffer
117-
118-
@param[in] Buffer Buffer whose attributes will be altered
119-
@param[in] Size Size of the buffer
120-
121-
@retval EFI_SUCCESS NX attribute removed, RO attribute applied
122-
@retval EFI_INVALID_PARAMETER Buffer is not page-aligned or Buffer is 0 or Size of buffer
123-
is not page-aligned
124-
@retval Other Return value of LocateProtocol, ClearMemoryAttributes, or SetMemoryAttributes
125-
**/
126-
EFI_STATUS
127-
BufferRemoveNoExecuteSetReadOnly (
128-
IN EFI_PHYSICAL_ADDRESS Buffer,
129-
IN UINTN Size
130-
)
131-
{
132-
EFI_CPU_ARCH_PROTOCOL *CpuProtocol = NULL;
133-
EFI_STATUS Status;
134-
135-
if ((Buffer == 0) || (Buffer % EFI_PAGE_SIZE != 0) || (Size % EFI_PAGE_SIZE != 0)) {
136-
return EFI_INVALID_PARAMETER;
137-
}
138-
139-
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuProtocol);
140-
141-
if (EFI_ERROR (Status)) {
142-
DEBUG ((DEBUG_ERROR, "%a - Unable to locate gEfiCpuArchProtocolGuid\n", __func__));
143-
ASSERT_EFI_ERROR (Status);
144-
return Status;
145-
}
146-
147-
Status = CpuProtocol->SetMemoryAttributes (
148-
CpuProtocol,
149-
Buffer,
150-
Size,
151-
EFI_MEMORY_RO
152-
);
153-
154-
if EFI_ERROR (Status) {
155-
DEBUG ((DEBUG_INFO, "%a - Unable to update buffer attributes!\n", __func__));
156-
ASSERT_EFI_ERROR (Status);
157-
}
158-
159-
return Status;
160-
}
161-
162-
// MU_CHANGE END Enable removal of NX attribute from buffer
163-
164111
/**
165112
Enable Debug Agent to support source debugging on AP function.
166113
@@ -550,32 +497,70 @@ AllocateApLoopCodeBuffer (
550497
/**
551498
Remove Nx protection for the range specific by BaseAddress and Length.
552499
553-
The PEI implementation uses CpuPageTableLib to change the attribute.
554-
The DXE implementation uses gDS to change the attribute.
500+
@param[in] BaseAddress BaseAddress of the range.
501+
@param[in] Length Length of the range.
502+
**/
503+
VOID
504+
RemoveNxProtection (
505+
IN EFI_PHYSICAL_ADDRESS BaseAddress,
506+
IN UINTN Length
507+
)
508+
{
509+
EFI_STATUS Status;
510+
EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
511+
512+
Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &MemDesc);
513+
if (!EFI_ERROR (Status)) {
514+
if (((MemDesc.Capabilities & EFI_MEMORY_XP) == EFI_MEMORY_XP) && ((MemDesc.Attributes & EFI_MEMORY_XP) == EFI_MEMORY_XP)) {
515+
Status = gDS->SetMemorySpaceAttributes (
516+
BaseAddress,
517+
Length,
518+
MemDesc.Attributes & (~EFI_MEMORY_XP)
519+
);
520+
521+
if (EFI_ERROR (Status)) {
522+
DEBUG ((DEBUG_ERROR, "%a - Setting Ro on 0x%p returned %r\n", __func__, BaseAddress, Status));
523+
ASSERT_EFI_ERROR (Status);
524+
}
525+
} else {
526+
DEBUG ((DEBUG_ERROR, "%a - Memory Address was not found in Memory map! %lp %r\n", __func__, BaseAddress, Status));
527+
ASSERT_EFI_ERROR (Status);
528+
}
529+
}
530+
}
531+
532+
/**
533+
Add ReadOnly protection to the range specified by BaseAddress and Length.
555534
556535
@param[in] BaseAddress BaseAddress of the range.
557536
@param[in] Length Length of the range.
558537
**/
559538
VOID
560-
RemoveNxprotection (
539+
ApplyReadOnlyMemoryProtection (
561540
IN EFI_PHYSICAL_ADDRESS BaseAddress,
562541
IN UINTN Length
563542
)
564543
{
565544
EFI_STATUS Status;
566545
EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
567546

568-
//
569-
// TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
570-
// service.
571-
//
572547
Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &MemDesc);
573548
if (!EFI_ERROR (Status)) {
574-
gDS->SetMemorySpaceAttributes (
575-
BaseAddress,
576-
Length,
577-
MemDesc.Attributes & (~EFI_MEMORY_XP)
578-
);
549+
if (((MemDesc.Capabilities & EFI_MEMORY_RO) == EFI_MEMORY_RO) && ((MemDesc.Attributes & EFI_MEMORY_RO) != EFI_MEMORY_RO)) {
550+
Status = gDS->SetMemorySpaceAttributes (
551+
BaseAddress,
552+
Length,
553+
MemDesc.Attributes | EFI_MEMORY_RO
554+
);
555+
556+
if (EFI_ERROR (Status)) {
557+
DEBUG ((DEBUG_ERROR, "%a - Setting Ro on 0x%p returned %r\n", __func__, BaseAddress, Status));
558+
ASSERT_EFI_ERROR (Status);
559+
}
560+
} else {
561+
DEBUG ((DEBUG_ERROR, "%a - Memory Address was not found in Memory map! %lp %r\n", __func__, BaseAddress, Status));
562+
ASSERT_EFI_ERROR (Status);
563+
}
579564
}
580565
}
581566

@@ -601,12 +586,15 @@ MpInitChangeApLoopCallback (
601586
CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();
602587
CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
603588
mNumberToFinish = CpuMpData->CpuCount - 1;
604-
// MU_CHANGE END Enable removal of NX attribute from buffer
605-
BufferRemoveNoExecuteSetReadOnly (
589+
RemoveNxProtection (
590+
(EFI_PHYSICAL_ADDRESS)(UINTN)mReservedApLoop.Data,
591+
EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (CpuMpData->AddressMap.RelocateApLoopFuncSizeAmdSev))
592+
);
593+
594+
ApplyReadOnlyMemoryProtection (
606595
(EFI_PHYSICAL_ADDRESS)(UINTN)mReservedApLoop.Data,
607596
EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (CpuMpData->AddressMap.RelocateApLoopFuncSizeAmdSev))
608597
);
609-
// MU_CHANGE END Enable removal of NX attribute from buffer
610598
WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);
611599
while (mNumberToFinish > 0) {
612600
CpuPause ();
@@ -691,7 +679,7 @@ InitMpGlobalData (
691679
MemDesc.Attributes | EFI_MEMORY_RP
692680
);
693681
ASSERT_EFI_ERROR (Status);
694-
AppendCpuMpDebugProtocolEntry (StackBase, CpuMpData->CpuApStackSize, Index, FALSE); // MU_CHANGE
682+
AppendCpuMpDebugProtocolEntry (StackBase, CpuMpData->CpuApStackSize, Index, FALSE); // MU_CHANGE
695683
DEBUG ((
696684
DEBUG_INFO,
697685
"Stack Guard set at %lx [cpu%lu]!\n",
@@ -700,7 +688,7 @@ InitMpGlobalData (
700688
));
701689
}
702690

703-
InstallCpuMpDebugProtocol (); // MU_CHANGE
691+
InstallCpuMpDebugProtocol (); // MU_CHANGE
704692
}
705693
// MU_CHANGE START: Add the Debug Protocol in the case that CpuStackGuard is not active
706694
else {

UefiCpuPkg/Library/MpInitLib/MpLib.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,10 +2261,7 @@ MpInitLibInitialize (
22612261
);
22622262
DEBUG ((DEBUG_INFO, "AP Vector: non-16-bit = %p/%x\n", CpuMpData->WakeupBufferHigh, ApResetVectorSizeAbove1Mb));
22632263

2264-
// MU_CHANGE START: Enable removal of NX attribute from buffer
2265-
BufferRemoveNoExecuteSetReadOnly (CpuMpData->WakeupBufferHigh, ALIGN_VALUE (ApResetVectorSizeAbove1Mb, EFI_PAGE_SIZE));
2266-
// MU_CHANGE END: Enable removal of NX attribute from buffer
2267-
2264+
ApplyReadOnlyMemoryProtection ((EFI_PHYSICAL_ADDRESS)(UINTN)CpuMpData->WakeupBufferHigh, ALIGN_VALUE (ApResetVectorSizeAbove1Mb, EFI_PAGE_SIZE));
22682265
//
22692266
// Save APIC mode for AP to sync
22702267
//
@@ -3492,14 +3489,15 @@ PrepareApLoopCode (
34923489
// Make sure that the buffer memory is executable if NX protection is enabled
34933490
// for EfiReservedMemoryType.
34943491
//
3495-
RemoveNxprotection (Address, EFI_PAGES_TO_SIZE (FuncPages));
3492+
RemoveNxProtection (Address, EFI_PAGES_TO_SIZE (FuncPages));
34963493
}
34973494

34983495
mReservedTopOfApStack = (UINTN)Address + EFI_PAGES_TO_SIZE (StackPages+FuncPages);
34993496
ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);
35003497
mReservedApLoop.Data = (VOID *)(UINTN)Address;
35013498
ASSERT (mReservedApLoop.Data != NULL);
35023499
CopyMem (mReservedApLoop.Data, ApLoopFunc, ApLoopFuncSize);
3500+
ApplyReadOnlyMemoryProtection (Address, EFI_PAGES_TO_SIZE (FuncPages));
35033501
if (!CpuMpData->UseSevEsAPMethod) {
35043502
//
35053503
// processors without SEV-ES and paging is enabled

UefiCpuPkg/Library/MpInitLib/MpLib.h

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -985,36 +985,25 @@ AllocateApLoopCodeBuffer (
985985
/**
986986
Remove Nx protection for the range specific by BaseAddress and Length.
987987
988-
The PEI implementation uses CpuPageTableLib to change the attribute.
989-
The DXE implementation uses gDS to change the attribute.
990-
991988
@param[in] BaseAddress BaseAddress of the range.
992989
@param[in] Length Length of the range.
993990
**/
994991
VOID
995-
RemoveNxprotection (
992+
RemoveNxProtection (
996993
IN EFI_PHYSICAL_ADDRESS BaseAddress,
997994
IN UINTN Length
998995
);
999996

1000-
// MU_CHANGE START: Enable removal of NX attribute from buffer
1001-
1002997
/**
1003-
Remove NX attribute from Buffer and apply RO to Buffer
998+
Add ReadOnly protection to the range specified by BaseAddress and Length.
1004999
1005-
@param[in] Buffer Buffer whose attributes will be altered
1006-
@param[in] Size Size of the buffer
1007-
1008-
@retval EFI_SUCCESS NX attribute removed, RO attribute applied
1009-
@retval EFI_INVALID_PARAMETER Buffer is not page-aligned or Buffer is 0 or Size of buffer
1010-
is not page-aligned
1011-
@retval Other Return value of LocateProtocol, ClearMemoryAttributes, or SetMemoryAttributes
1000+
@param[in] BaseAddress BaseAddress of the range.
1001+
@param[in] Length Length of the range.
10121002
**/
1013-
EFI_STATUS
1014-
BufferRemoveNoExecuteSetReadOnly (
1015-
IN EFI_PHYSICAL_ADDRESS Buffer,
1016-
IN UINTN Size
1003+
VOID
1004+
ApplyReadOnlyMemoryProtection (
1005+
IN EFI_PHYSICAL_ADDRESS BaseAddress,
1006+
IN UINTN Length
10171007
);
10181008

1019-
// MU_CHANGE END: Enable removal of NX attribute from buffer
10201009
#endif

UefiCpuPkg/Library/MpInitLib/PeiMpLib.c

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,6 @@
1414

1515
STATIC UINT64 mSevEsPeiWakeupBuffer = BASE_1MB;
1616

17-
// MU_CHANGE START: Enable removal of NX attribute from buffer
18-
19-
/**
20-
Remove NX attribute from Buffer and apply RO to Buffer
21-
22-
@param[in] Buffer Buffer whose attributes will be altered
23-
@param[in] Size Size of the buffer
24-
25-
@retval EFI_SUCCESS NX attribute removed, RO attribute applied
26-
@retval EFI_INVALID_PARAMETER Buffer is not page-aligned or Buffer is 0 or Size of buffer
27-
is not page-aligned
28-
@retval Other Return value of LocateProtocol, ClearMemoryAttributes, or SetMemoryAttributes
29-
**/
30-
EFI_STATUS
31-
BufferRemoveNoExecuteSetReadOnly (
32-
IN EFI_PHYSICAL_ADDRESS Buffer,
33-
IN UINTN Size
34-
)
35-
{
36-
return EFI_SUCCESS;
37-
}
38-
39-
// MU_CHANGE End: Enable removal of NX attribute from buffer
40-
4117
/**
4218
Enable Debug Agent to support source debugging on AP function.
4319
@@ -877,14 +853,11 @@ AllocateApLoopCodeBuffer (
877853
/**
878854
Remove Nx protection for the range specific by BaseAddress and Length.
879855
880-
The PEI implementation uses CpuPageTableLib to change the attribute.
881-
The DXE implementation uses gDS to change the attribute.
882-
883856
@param[in] BaseAddress BaseAddress of the range.
884857
@param[in] Length Length of the range.
885858
**/
886859
VOID
887-
RemoveNxprotection (
860+
RemoveNxProtection (
888861
IN EFI_PHYSICAL_ADDRESS BaseAddress,
889862
IN UINTN Length
890863
)
@@ -960,6 +933,22 @@ RemoveNxprotection (
960933
AsmWriteCr3 (PageTable);
961934
}
962935

936+
/**
937+
Add ReadOnly protection to the range specified by BaseAddress and Length.
938+
939+
@param[in] BaseAddress BaseAddress of the range.
940+
@param[in] Length Length of the range.
941+
**/
942+
VOID
943+
ApplyReadOnlyMemoryProtection (
944+
IN EFI_PHYSICAL_ADDRESS BaseAddress,
945+
IN UINTN Length
946+
)
947+
{
948+
// stub for now, page tables are limited in PEI
949+
return;
950+
}
951+
963952
// MU_CHANGE START: Support for protocol for reporting multi-processor debug info
964953

965954
/**

0 commit comments

Comments
 (0)