Skip to content

Commit

Permalink
Add Memory Protection Debug Protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
TaylorBeebe authored and kenlautner committed May 4, 2023
1 parent 0df0cca commit b57bda6
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 38 deletions.
1 change: 1 addition & 0 deletions MdeModulePkg/Core/Dxe/DxeMain.inf
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
gEfiCapsuleArchProtocolGuid ## CONSUMES
gEfiWatchdogTimerArchProtocolGuid ## CONSUMES
gEfiCpu2ProtocolGuid ## SOMETIMES_CONSUMES ## MS_CHANGE
gMemoryProtectionDebugProtocolGuid ## SOMETIMES_PRODUCES ## MS_CHANGE
gEfiMemoryAttributeProtocolGuid ## CONSUMES ## MS_CHANGE
gMemoryProtectionSpecialRegionProtocolGuid ## PRODUCES ## MU_CHANGE

Expand Down
13 changes: 8 additions & 5 deletions MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#include <Protocol/FirmwareVolume2.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/MemoryProtectionDebug.h> // MU_CHANGE
#include <Protocol/MemoryAttribute.h> // MU_CHANGE

#include "DxeMain.h"
Expand Down Expand Up @@ -72,8 +73,10 @@ EFI_MEMORY_ATTRIBUTE_PROTOCOL *mMemoryAttribute = NULL; // MU_CHANGE

STATIC LIST_ENTRY mProtectedImageRecordList;
// MS_CHANGE - START
STATIC HEAP_GUARD_DEBUG_PROTOCOL mHeapGuardDebug = {
IsGuardPage
STATIC MEMORY_PROTECTION_DEBUG_PROTOCOL mMemoryProtectionDebug =
{
IsGuardPage,
GetImageList
};
// MS_CHANGE - END

Expand Down Expand Up @@ -1415,11 +1418,11 @@ CoreInitializeMemoryProtection (
EFI_HANDLE HgBmHandle = NULL;
Status = CoreInstallMultipleProtocolInterfaces (
&HgBmHandle,
&gHeapGuardDebugProtocolGuid,
&mHeapGuardDebug,
&gMemoryProtectionDebugProtocolGuid,
&mMemoryProtectionDebug,
NULL
);
DEBUG ((DEBUG_INFO, "Installed gHeapGuardDebugProtocolGuid - %r\n", Status));
DEBUG ((DEBUG_INFO, "Installed gMemoryProtectionDebugProtocolGuid - %r\n", Status));
}

// MSCHANGE END
Expand Down
135 changes: 135 additions & 0 deletions MdeModulePkg/Core/Dxe/Misc/MemoryProtectionSupport.c
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,141 @@ GetImageRecordContainedByBuffer (
return NULL;
}

/**
Generate a list of IMAGE_RANGE_DESCRIPTOR structs which describe the data/code regions of protected images or
the memory ranges of nonprotected images.
@param[in] ImageList Pointer to NULL IMAGE_RANGE_DESCRIPTOR* which will be updated to the head of the allocated
IMAGE_RANGE_DESCRIPTOR list
@param[in] ProtectedOrNonProtected Enum describing if the returned list will describe the protected or
nonprotected loaded images
@retval EFI_SUCCESS *ImageList points to the head of the IMAGE_RANGE_DESCRIPTOR list
@retval EFI_INVALID_PARAMETER ImageList is NULL or *ImageList is not NULL
@retval EFI_OUT_OF_RESOURCES Allocation of memory failed
**/
EFI_STATUS
EFIAPI
GetImageList (
IN IMAGE_RANGE_DESCRIPTOR **ImageList,
IN IMAGE_RANGE_PROTECTION_STATUS ProtectedOrNonProtected
)
{
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
LIST_ENTRY *ImageRecordCodeSectionLink;
LIST_ENTRY *ImageRecordCodeSectionEndLink;
LIST_ENTRY *ImageRecordCodeSectionList;
IMAGE_PROPERTIES_RECORD *ImageRecord;
LIST_ENTRY *ImageRecordLink;
LIST_ENTRY *ImageListHead;
UINT64 PhysicalStart, PhysicalEnd;
IMAGE_RANGE_DESCRIPTOR *CurrentImageRangeDescriptor;

if ((ImageList == NULL) || (*ImageList != NULL)) {
return EFI_INVALID_PARAMETER;
}

if (ProtectedOrNonProtected == Protected) {
ImageListHead = &mImagePropertiesPrivate.ImageRecordList;
} else if (ProtectedOrNonProtected == NonProtected) {
ImageListHead = &mNonProtectedImageRangesPrivate.NonProtectedImageList;
} else {
return EFI_INVALID_PARAMETER;
}

*ImageList = AllocateZeroPool (sizeof (IMAGE_RANGE_DESCRIPTOR));

if (*ImageList == NULL) {
return EFI_OUT_OF_RESOURCES;
}

InitializeListHead (&(*ImageList)->Link);

// Walk through each image
for (ImageRecordLink = ImageListHead->ForwardLink;
ImageRecordLink != ImageListHead;
ImageRecordLink = ImageRecordLink->ForwardLink)
{
ImageRecord = CR (
ImageRecordLink,
IMAGE_PROPERTIES_RECORD,
Link,
IMAGE_PROPERTIES_RECORD_SIGNATURE
);
PhysicalStart = ImageRecord->ImageBase;
PhysicalEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;

ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;

ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
ImageRecordCodeSection = CR (
ImageRecordCodeSectionLink,
IMAGE_PROPERTIES_RECORD_CODE_SECTION,
Link,
IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
);
ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;

// Mark the data region
if (PhysicalStart < ImageRecordCodeSection->CodeSegmentBase) {
CurrentImageRangeDescriptor = AllocatePool (sizeof (IMAGE_RANGE_DESCRIPTOR));
if (CurrentImageRangeDescriptor == NULL) {
goto OutOfResourcesCleanup;
}

POPULATE_IMAGE_RANGE_DESCRIPTOR (CurrentImageRangeDescriptor, Data, PhysicalStart, ImageRecordCodeSection->CodeSegmentBase - PhysicalStart);
PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
InsertTailList (&(*ImageList)->Link, &CurrentImageRangeDescriptor->Link);
}

// Mark the code region
CurrentImageRangeDescriptor = AllocatePool (sizeof (IMAGE_RANGE_DESCRIPTOR));
if (CurrentImageRangeDescriptor == NULL) {
goto OutOfResourcesCleanup;
}

POPULATE_IMAGE_RANGE_DESCRIPTOR (CurrentImageRangeDescriptor, Code, PhysicalStart, ImageRecordCodeSection->CodeSegmentSize);
PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
InsertTailList (&(*ImageList)->Link, &CurrentImageRangeDescriptor->Link);
}

// Mark the remainder of the image as a data section
if (PhysicalStart < PhysicalEnd) {
CurrentImageRangeDescriptor = AllocatePool (sizeof (IMAGE_RANGE_DESCRIPTOR));
if (CurrentImageRangeDescriptor == NULL) {
goto OutOfResourcesCleanup;
}

POPULATE_IMAGE_RANGE_DESCRIPTOR (CurrentImageRangeDescriptor, Data, PhysicalStart, PhysicalEnd - PhysicalStart);
PhysicalStart = PhysicalEnd;
InsertTailList (&(*ImageList)->Link, &CurrentImageRangeDescriptor->Link);
}
}

return EFI_SUCCESS;

OutOfResourcesCleanup:
ImageRecordLink = &(*ImageList)->Link;

while (!IsListEmpty (ImageRecordLink)) {
CurrentImageRangeDescriptor = CR (
ImageRecordLink->ForwardLink,
IMAGE_RANGE_DESCRIPTOR,
Link,
IMAGE_RANGE_DESCRIPTOR_SIGNATURE
);

RemoveEntryList (&CurrentImageRangeDescriptor->Link);
FreePool (CurrentImageRangeDescriptor);
}

FreePool (*ImageList);

return EFI_OUT_OF_RESOURCES;
}

/**
Create an image properties record and insert it into the nonprotected image list
Expand Down
20 changes: 20 additions & 0 deletions MdeModulePkg/Core/Dxe/Misc/MemoryProtectionSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,24 @@ IsSystemNxCompatible (
VOID
);

/**
Generate a list of IMAGE_RANGE_DESCRIPTOR structs which describe the data/code regions of protected images or
the memory ranges of nonprotected images.
@param[in] ImageList Pointer to NULL IMAGE_RANGE_DESCRIPTOR* which will be updated to the head of the allocated
IMAGE_RANGE_DESCRIPTOR list
@param[in] ProtectedOrNonProtected Enum describing if the returned list will describe the protected or
nonprotected loaded images
@retval EFI_SUCCESS *ImageList points to the head of the IMAGE_RANGE_DESCRIPTOR list
@retval EFI_INVALID_PARAMETER ImageList is NULL or *ImageList is not NULL
@retval EFI_OUT_OF_RESOURCES Allocation of memory failed
**/
EFI_STATUS
EFIAPI
GetImageList (
IN IMAGE_RANGE_DESCRIPTOR **ImageList,
IN IMAGE_RANGE_PROTECTION_STATUS ProtectedOrNonProtected
);

#endif
33 changes: 0 additions & 33 deletions MdeModulePkg/Include/Protocol/HeapGuardDebug.h

This file was deleted.

62 changes: 62 additions & 0 deletions MdeModulePkg/Include/Protocol/MemoryProtectionDebug.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/** @file -- MemoryProtectionDebug.h
This protocol provides debug access to memory protection functionality for validation and testing.
This protocol will be installed on every boot, so no functionality exposed within should be
a sensitive or a security concern. Any potentially sensitive debug info/logic which needs to be exposed
for testing should be attached to a new protocol whose installation is blocked behind a check
that the device is not for broad consumer use (manufacturing mode, unit test mode, etc.).
Copyright (c) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef __MEMORY_PROTECTION_DEBUG_PROTOCOL__
#define __MEMORY_PROTECTION_DEBUG_PROTOCOL__

#define MEMORY_PROTECTION_DEBUG_PROTOCOL_GUID \
{ \
0xe8150630, 0x6366, 0x4294, { 0xa3, 0x47, 0x89, 0x2c, 0x3a, 0x7d, 0xe4, 0xaf } \
}

#define IMAGE_RANGE_DESCRIPTOR_SIGNATURE SIGNATURE_32 ('I','R','D','S')

typedef enum _IMAGE_RANGE_TYPE {
Code,
Data
} IMAGE_RANGE_TYPE;

typedef enum _IMAGE_RANGE_PROTECTION_STATUS {
Protected,
NonProtected
} IMAGE_RANGE_PROTECTION_STATUS;

typedef struct _IMAGE_RANGE_DESCRIPTOR {
UINT32 Signature;
LIST_ENTRY Link;
EFI_PHYSICAL_ADDRESS Base;
EFI_PHYSICAL_ADDRESS Length;
IMAGE_RANGE_TYPE Type;
} IMAGE_RANGE_DESCRIPTOR;

typedef
BOOLEAN
(EFIAPI *IS_GUARD_PAGE)(
EFI_PHYSICAL_ADDRESS Address
);

typedef
EFI_STATUS
(EFIAPI *GET_IMAGE_LIST)(
IMAGE_RANGE_DESCRIPTOR **ImageList,
IMAGE_RANGE_PROTECTION_STATUS ProtectedOrNonProtected
);

typedef struct _MEMORY_PROTECTION_DEBUG_PROTOCOL {
IS_GUARD_PAGE IsGuardPage;
GET_IMAGE_LIST GetImageList;
} MEMORY_PROTECTION_DEBUG_PROTOCOL;

extern EFI_GUID gMemoryProtectionDebugProtocolGuid;

#endif

0 comments on commit b57bda6

Please sign in to comment.