Skip to content

Commit

Permalink
Add Adv Logger PRM Module
Browse files Browse the repository at this point in the history
This commit adds the Adv Logger PRM Module. It is an alternate
way to fetch the Adv Logger Log that does not require SMM/Secure World
access. It also is independently serviceable from the OS.

- [x] Impacts functionality?
- **Functionality** - Does the change ultimately impact how firmware
functions?
- Examples: Add a new library, publish a new PPI, update an algorithm,
...
- [x] Impacts security?
- **Security** - Does the change have a direct security impact on an
application,
    flow, or firmware?
  - Examples: Crypto algorithm change, buffer overflow fix, parameter
    validation improvement, ...
- [ ] Breaking change?
- **Breaking change** - Will anyone consuming this change experience a
break
    in build or boot behavior?
- Examples: Add a new library class, move a module to a different repo,
call
    a function in a new library class in a pre-existing module, ...
- [x] Includes tests?
  - **Tests** - Does the change include any explicit test code?
  - Examples: Unit tests, integration tests, robot tests, ...
- [x] Includes documentation?
- **Documentation** - Does the change contain explicit documentation
additions
    outside direct code modifications (and comments)?
- Examples: Update readme file, add feature readme file, link to
documentation
    on an a separate Web page, ...

Tested on various physical and virtual platforms to ensure the
log was the same between the GetVariable interface and the PRM
interface.

See the README update for integration instructions.
  • Loading branch information
os-d committed May 2, 2024
1 parent be9a3d2 commit 8d7bae0
Show file tree
Hide file tree
Showing 21 changed files with 2,324 additions and 6 deletions.
164 changes: 164 additions & 0 deletions AdvLoggerPkg/AdvLoggerOsConnectorPrm/AdvLoggerOsConnectorPrm.c
@@ -0,0 +1,164 @@
/** @file AdvLoggerOsConnectorPrm.c
This driver gives an interface to OS components to fetch the AdvancedLogger memory log.
Copyright (c) Microsoft Corporation
SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include <Uefi.h>
#include <PrmModule.h>

#include <Library/BaseLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
#include <AdvancedLoggerInternal.h>

#include "AdvLoggerOsConnectorPrm.h"

typedef struct {
VOID *OutputBuffer;
UINT32 *OutputBufferSize;
} ADVANCED_LOGGER_PRM_PARAMETER_BUFFER;

/**
CheckAddress
The address of the ADVANCE_LOGGER_INFO block pointer is captured before END_OF_DXE.
LogBufferOffset, LogCurrentOffset, and LogBufferSize, could be written to by untrusted code. Here, we check that
the offsets are within the allocated mLoggerInfo space, and that LogBufferSize, which is used in multiple places
to see if a new message will fit into the log buffer, is valid.
@param DataBuf PRM static data buffer containing LoggerInfo pointer
@return BOOLEAN TRUE - LoggerInfo passes security checks
@return BOOLEAN FALSE- LoggerInfo failed security checks
**/
STATIC
BOOLEAN
ValidateInfoBlock (
IN ADV_LOGGER_PRM_DATA_BUFFER *DataBuf
)
{
if ((DataBuf == NULL) || (DataBuf->LoggerInfo == NULL)) {
return FALSE;
}

if (DataBuf->LoggerInfo->Signature != ADVANCED_LOGGER_SIGNATURE) {
return FALSE;
}

// most ValidateInfoBlocks check if LogBufferOffset == sizeof (*LoggerInfo)
// we can't do that in the PRM because it is independently serviceable at OS runtime
// we may be paired with a FW that has a different logger info structure size, so
// we have to go based on what the boot time FW tells us

if ((DataBuf->LoggerInfo->LogCurrentOffset > TOTAL_LOG_SIZE_WITH_ALI (DataBuf->LoggerInfo)) ||
(DataBuf->LoggerInfo->LogCurrentOffset < DataBuf->LoggerInfo->LogBufferOffset))
{
return FALSE;
}

// ensure that the passed in sizes match what we see in the advanced logger structure
if ((DataBuf->ExpectedLogSize != DataBuf->LoggerInfo->LogBufferSize) ||
(DataBuf->ExpectedHeaderSize != DataBuf->LoggerInfo->LogBufferOffset))
{
return FALSE;
}

return TRUE;
}

/**
The Advanced Logger Os Connector PRM handler.
This handler reads the AdvancedLogger buffer and copies the data to the caller supplied buffer.
@param[in] ParameterBuffer A pointer to the PRM handler parameter buffer
@param[in] ContextBuffer A pointer to the PRM handler context buffer
@retval EFI_STATUS The PRM handler executed successfully.
@retval Others An error occurred in the PRM handler.
**/
PRM_HANDLER_EXPORT (AdvLoggerOsConnectorPrmHandler) {
ADVANCED_LOGGER_PRM_PARAMETER_BUFFER *ParamBuf;
ADV_LOGGER_PRM_DATA_BUFFER *DataBuf = NULL;

if ((ParameterBuffer == NULL) || (ContextBuffer == NULL)) {
return EFI_INVALID_PARAMETER;
}

if (ContextBuffer->StaticDataBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}

//
// Verify PRM data buffer signature is valid
//
if (
(ContextBuffer->Signature != PRM_CONTEXT_BUFFER_SIGNATURE) ||
(ContextBuffer->StaticDataBuffer->Header.Signature != PRM_DATA_BUFFER_HEADER_SIGNATURE))
{
return EFI_NOT_FOUND;
}

DataBuf = (ADV_LOGGER_PRM_DATA_BUFFER *)ContextBuffer->StaticDataBuffer->Data;

if (!ValidateInfoBlock (DataBuf)) {
return EFI_COMPROMISED_DATA;
}

ParamBuf = (ADVANCED_LOGGER_PRM_PARAMETER_BUFFER *)ParameterBuffer;

if (ParamBuf->OutputBufferSize == NULL) {
return EFI_INVALID_PARAMETER;
}

if (*(ParamBuf->OutputBufferSize) < DataBuf->ExpectedLogSize + DataBuf->ExpectedHeaderSize) {
*ParamBuf->OutputBufferSize = DataBuf->ExpectedLogSize + DataBuf->ExpectedHeaderSize;
return EFI_BUFFER_TOO_SMALL;
}

if (ParamBuf->OutputBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}

//
// The length to copy we take from the static data buffer, populated by the FW from a fixed at build PCD
// We do this so we do not have to trust the writeable LoggerInfo structure. We confirm the header size and
// data size against the structure's values to ensure they match
//
CopyMem (ParamBuf->OutputBuffer, (CONST VOID *)DataBuf->LoggerInfo, DataBuf->ExpectedLogSize + DataBuf->ExpectedHeaderSize);

return EFI_SUCCESS;
}

//
// Register the PRM export information for this PRM Module
//
PRM_MODULE_EXPORT (
PRM_HANDLER_EXPORT_ENTRY (ADVANCED_LOGGER_OS_CONNECTOR_PRM_HANDLER_GUID, AdvLoggerOsConnectorPrmHandler)
);

/**
Module entry point.
@param[in] ImageHandle The image handle.
@param[in] SystemTable A pointer to the system table.
@retval EFI_SUCCESS This function always returns success.
**/
EFI_STATUS
EFIAPI
AdvLoggerOsConnectorPrmEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EFI_SUCCESS;
}
36 changes: 36 additions & 0 deletions AdvLoggerPkg/AdvLoggerOsConnectorPrm/AdvLoggerOsConnectorPrm.h
@@ -0,0 +1,36 @@
/** @file AdvLoggerOsConnectorPrm.h
Definitions to share between the AdvLogger PRM and PRM config lib
Copyright (C) Microsoft Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef ADV_LOGGER_OS_CONNECTOR_PRM_H_
#define ADV_LOGGER_OS_CONNECTOR_PRM_H_

// {B4DFA4A2-EAD0-4F55-998B-EA5BE68F73FD}
STATIC CONST EFI_GUID mPrmModuleGuid = {
0xb4dfa4a2, 0xead0, 0x4f55, { 0x99, 0x8b, 0xea, 0x5b, 0xe6, 0x8f, 0x73, 0xfd }
};

// {0f8aef11-77b8-4d7f-84cc-fe0cce64ac14}
STATIC CONST EFI_GUID mAdvLoggerOsConnectorPrmHandlerGuid = {
0x0f8aef11, 0x77b8, 0x4d7f, { 0x84, 0xcc, 0xfe, 0x0c, 0xce, 0x64, 0xac, 0x14 }
};

// {0f8aef11-77b8-4d7f-84cc-fe0cce64ac14}
#define ADVANCED_LOGGER_OS_CONNECTOR_PRM_HANDLER_GUID {0x0f8aef11, 0x77b8, 0x4d7f, {0x84, 0xcc, 0xfe, 0x0c, 0xce, 0x64, 0xac, 0x14}}

#pragma pack (push, 1)

typedef struct {
ADVANCED_LOGGER_INFO *LoggerInfo;
UINT32 ExpectedLogSize;
UINT32 ExpectedHeaderSize;
} ADV_LOGGER_PRM_DATA_BUFFER;

#pragma pack (pop)

#endif // ADV_LOGGER_OS_CONNECTOR_PRM_H_
42 changes: 42 additions & 0 deletions AdvLoggerPkg/AdvLoggerOsConnectorPrm/AdvLoggerOsConnectorPrm.inf
@@ -0,0 +1,42 @@
## @file
# AdvancedLogger OS Connector PRM Driver
#
# This driver gives an interface to OS components to fetch/clear the AdvancedLogger memory log.
#
# Copyright (c) Microsoft Corporation
# SPDX-License-Identifier: BSD-2-Clause-Patent
##

[Defines]
INF_VERSION = 1.17
BASE_NAME = AdvLoggerOsConnectorPrm
FILE_GUID = B4DFA4A2-EAD0-4F55-998B-EA5BE68F73FD
MODULE_TYPE = DXE_RUNTIME_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = AdvLoggerOsConnectorPrmEntry

[Sources]
AdvLoggerOsConnectorPrm.c

[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
PrmPkg/PrmPkg.dec
AdvLoggerPkg/AdvLoggerPkg.dec

[LibraryClasses]
BaseLib
PrintLib
UefiDriverEntryPoint
UefiLib
BaseMemoryLib

[Depex]
TRUE

[BuildOptions.common]
MSFT:*_*_*_DLINK_FLAGS = /DLL /SUBSYSTEM:CONSOLE /VERSION:1.0
MSFT:*_*_*_GENFW_FLAGS = --keepoptionalheader

GCC:*_*_AARCH64_GENFW_FLAGS = --keepoptionalheader --prm
GCC:*_*_AARCH64_DLINK_FLAGS = -Wl,--no-gc-sections -Wl,--require-defined=PrmModuleExportDescriptor -Wl,--require-defined=CheckStaticDataBufferPrmHandler

0 comments on commit 8d7bae0

Please sign in to comment.