Skip to content

Commit 21cbba1

Browse files
os-dmergify[bot]
authored andcommitted
StandaloneMmPkg: Call PeCoffLoaderUnloadImage When Unloading Image
Today, StandaloneMmCore calls PeCoffLoaderRelocateImage() when loading images, which calls PeCoffLoaderRelocateImageExtraAction(). On AARCH64, this sets the image memory protections accordingly, RO + E on code sections, RW + NX on data sections. However, if an image fails to start (i.e. its entry point returns a failure) StandaloneMmCore does not call the corresponding PeCoffLoaderUnloadImage, which calls PeCoffLoaderUnloadImageExtraAction, which on AARCH64 undoes the memory protections on the image, setting the whole memory region back to RW + NX. The core then frees this memory and the next allocation attempts to use it, which results in a data abort if a read only memory region is attempted to be written to. Theoretically, other instances of the PeCoffExtraActionLib could take other actions and so regardless of architecture, the contract with the PeCoffLoader should be maintained. This patch calls PeCoffLoaderUnloadImage when an image's entry point returns a failure, before freeing the image memory. This meets the contract and follows the DXE core behavior. Signed-off-by: Oliver Smith-Denny <[email protected]>
1 parent 9bb11ca commit 21cbba1

File tree

1 file changed

+42
-29
lines changed

1 file changed

+42
-29
lines changed

StandaloneMmPkg/Core/Dispatcher.c

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -101,40 +101,45 @@ BOOLEAN gRequestDispatch = FALSE;
101101
Loads an EFI image into SMRAM.
102102
103103
@param DriverEntry EFI_MM_DRIVER_ENTRY instance
104+
@param ImageContext Allocated ImageContext to be filled out by this function
104105
105106
@return EFI_STATUS
106107
107108
**/
108109
EFI_STATUS
109110
EFIAPI
110111
MmLoadImage (
111-
IN OUT EFI_MM_DRIVER_ENTRY *DriverEntry
112+
IN OUT EFI_MM_DRIVER_ENTRY *DriverEntry,
113+
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
112114
)
113115
{
114-
UINTN PageCount;
115-
EFI_STATUS Status;
116-
EFI_PHYSICAL_ADDRESS DstBuffer;
117-
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
116+
UINTN PageCount;
117+
EFI_STATUS Status;
118+
EFI_PHYSICAL_ADDRESS DstBuffer;
118119

119120
DEBUG ((DEBUG_INFO, "MmLoadImage - %g\n", &DriverEntry->FileName));
120121

122+
if (ImageContext == NULL) {
123+
return EFI_INVALID_PARAMETER;
124+
}
125+
121126
Status = EFI_SUCCESS;
122127

123128
//
124129
// Initialize ImageContext
125130
//
126-
ImageContext.Handle = DriverEntry->Pe32Data;
127-
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
131+
ImageContext->Handle = DriverEntry->Pe32Data;
132+
ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory;
128133

129134
//
130135
// Get information about the image being loaded
131136
//
132-
Status = PeCoffLoaderGetImageInfo (&ImageContext);
137+
Status = PeCoffLoaderGetImageInfo (ImageContext);
133138
if (EFI_ERROR (Status)) {
134139
return Status;
135140
}
136141

137-
PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
142+
PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext->ImageSize + ImageContext->SectionAlignment);
138143
DstBuffer = (UINTN)(-1);
139144

140145
Status = MmAllocatePages (
@@ -148,18 +153,18 @@ MmLoadImage (
148153
return Status;
149154
}
150155

151-
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
156+
ImageContext->ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
152157

153158
//
154159
// Align buffer on section boundary
155160
//
156-
ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
157-
ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
161+
ImageContext->ImageAddress += ImageContext->SectionAlignment - 1;
162+
ImageContext->ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext->SectionAlignment - 1));
158163

159164
//
160165
// Load the image to our new buffer
161166
//
162-
Status = PeCoffLoaderLoadImage (&ImageContext);
167+
Status = PeCoffLoaderLoadImage (ImageContext);
163168
if (EFI_ERROR (Status)) {
164169
MmFreePages (DstBuffer, PageCount);
165170
return Status;
@@ -168,21 +173,23 @@ MmLoadImage (
168173
//
169174
// Relocate the image in our new buffer
170175
//
171-
Status = PeCoffLoaderRelocateImage (&ImageContext);
176+
Status = PeCoffLoaderRelocateImage (ImageContext);
172177
if (EFI_ERROR (Status)) {
178+
// if relocate fails, we don't need to call unload image here, as the extra action that may change page attributes
179+
// only is called on a successful return
173180
MmFreePages (DstBuffer, PageCount);
174181
return Status;
175182
}
176183

177184
//
178185
// Flush the instruction cache so the image data are written before we execute it
179186
//
180-
InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
187+
InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext->ImageAddress, (UINTN)ImageContext->ImageSize);
181188

182189
//
183190
// Save Image EntryPoint in DriverEntry
184191
//
185-
DriverEntry->ImageEntryPoint = ImageContext.EntryPoint;
192+
DriverEntry->ImageEntryPoint = ImageContext->EntryPoint;
186193
DriverEntry->ImageBuffer = DstBuffer;
187194
DriverEntry->NumberOfPage = PageCount;
188195

@@ -197,7 +204,7 @@ MmLoadImage (
197204
DriverEntry->LoadedImage.FilePath = NULL;
198205

199206
DriverEntry->LoadedImage.ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer;
200-
DriverEntry->LoadedImage.ImageSize = ImageContext.ImageSize;
207+
DriverEntry->LoadedImage.ImageSize = ImageContext->ImageSize;
201208
DriverEntry->LoadedImage.ImageCodeType = EfiRuntimeServicesCode;
202209
DriverEntry->LoadedImage.ImageDataType = EfiRuntimeServicesData;
203210

@@ -223,18 +230,18 @@ MmLoadImage (
223230
DEBUG ((
224231
DEBUG_INFO | DEBUG_LOAD,
225232
"Loading MM driver at 0x%11p EntryPoint=0x%11p ",
226-
(VOID *)(UINTN)ImageContext.ImageAddress,
227-
FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)
233+
(VOID *)(UINTN)ImageContext->ImageAddress,
234+
FUNCTION_ENTRY_POINT (ImageContext->EntryPoint)
228235
));
229236

230237
//
231238
// Print Module Name by Pdb file path.
232239
// Windows and Unix style file path are all trimmed correctly.
233240
//
234-
if (ImageContext.PdbPointer != NULL) {
241+
if (ImageContext->PdbPointer != NULL) {
235242
StartIndex = 0;
236-
for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {
237-
if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) {
243+
for (Index = 0; ImageContext->PdbPointer[Index] != 0; Index++) {
244+
if ((ImageContext->PdbPointer[Index] == '\\') || (ImageContext->PdbPointer[Index] == '/')) {
238245
StartIndex = Index + 1;
239246
}
240247
}
@@ -245,7 +252,7 @@ MmLoadImage (
245252
// If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary.
246253
//
247254
for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
248-
EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex];
255+
EfiFileName[Index] = ImageContext->PdbPointer[Index + StartIndex];
249256
if (EfiFileName[Index] == 0) {
250257
EfiFileName[Index] = '.';
251258
}
@@ -381,11 +388,12 @@ MmDispatcher (
381388
VOID
382389
)
383390
{
384-
EFI_STATUS Status;
385-
LIST_ENTRY *Link;
386-
EFI_MM_DRIVER_ENTRY *DriverEntry;
387-
BOOLEAN ReadyToRun;
388-
BOOLEAN PreviousMmEntryPointRegistered;
391+
EFI_STATUS Status;
392+
LIST_ENTRY *Link;
393+
EFI_MM_DRIVER_ENTRY *DriverEntry;
394+
BOOLEAN ReadyToRun;
395+
BOOLEAN PreviousMmEntryPointRegistered;
396+
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
389397

390398
DEBUG ((DEBUG_INFO, "MmDispatcher\n"));
391399

@@ -424,7 +432,7 @@ MmDispatcher (
424432
// skip the LoadImage
425433
//
426434
if (DriverEntry->ImageHandle == NULL) {
427-
Status = MmLoadImage (DriverEntry);
435+
Status = MmLoadImage (DriverEntry, &ImageContext);
428436

429437
//
430438
// Update the driver state to reflect that it's been loaded
@@ -461,6 +469,11 @@ MmDispatcher (
461469
Status = ((MM_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, &gMmCoreMmst);
462470
if (EFI_ERROR (Status)) {
463471
DEBUG ((DEBUG_INFO, "StartImage Status - %r\n", Status));
472+
473+
// we need to unload the image before we free the pages. On some architectures (e.g. x86), this is a no-op, but
474+
// on others (e.g. AARCH64) this will remove the image memory protections set on the region so that when the
475+
// memory is freed, it has the default attributes set and can be used generically
476+
PeCoffLoaderUnloadImage (&ImageContext);
464477
MmFreePages (DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
465478
if (DriverEntry->ImageHandle != NULL) {
466479
MmUninstallProtocolInterface (

0 commit comments

Comments
 (0)