Skip to content

Commit

Permalink
Update BootAuditTestApp to Correctly Test Load Option Variables (#256)
Browse files Browse the repository at this point in the history
## Description

BootAuditTestApp tests the variable policy for the SysPrep####,
PlatformRecovery####, and Driver#### variables by attempting to get and
set the variables. When calling SetVariable with one of these three
variables, VarCheckLib will sanity check the variable data and return
EFI_INVALID_PARAMETER if the data is not a valid load option. Because we
want to check if the variables are writable, we need to create properly
formatted data before calling SetVariable.

This PR uses the DevicePath of the running EFI application to create a
load option to properly test the writability of the boot option
variables securely.

Fixes Issue #252

- [x] Impacts functionality?
- **Functionality** - Does the change ultimately impact how firmware
functions?
- Examples: Add a new library, publish a new PPI, update an algorithm,
...
- [ ] 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, ...
- [ ] 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, ...

## How This Was Tested

Tested on Q35

## Integration Instructions

N/A
  • Loading branch information
TaylorBeebe committed Jun 7, 2023
1 parent 933c7b2 commit 8502050
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 33 deletions.
203 changes: 171 additions & 32 deletions UefiTestingPkg/AuditTests/BootAuditTest/UEFI/BootAuditTestApp.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,35 +31,147 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UnitTestLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiBootManagerLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/FileHandleLib.h>

#define UNIT_TEST_APP_NAME "BootAuditTestApp"
#define UNIT_TEST_APP_VERSION "1.0"
#define UNIT_TEST_APP_NAME "BootAuditTestApp"
#define UNIT_TEST_APP_FILENAME L"BootAuditTestApp.efi"
#define UNIT_TEST_APP_VERSION "1.1"

typedef struct {
CHAR16 *TestName;
UINT32 Attributes;
CHAR16 *VariableDeleteName;
EFI_STATUS ExpectedStatus1a;
EFI_STATUS ExpectedStatus1b;
EFI_STATUS ExpectedStatus2;
CHAR16 *TestName;
UINT32 Attributes;
CHAR16 *VariableDeleteName;
EFI_STATUS ExpectedStatus1a;
EFI_STATUS ExpectedStatus1b;
EFI_STATUS ExpectedStatus2;
EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
} BASIC_TEST_CONTEXT;

// *----------------------------------------------------------------------------------*
// * Test Contexts *
// *----------------------------------------------------------------------------------*
static BASIC_TEST_CONTEXT mTest1 = { EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_SUCCESS, 0, EFI_WRITE_PROTECTED };
static BASIC_TEST_CONTEXT mTest2 = { EFI_SYS_PREP_ORDER_VARIABLE_NAME, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED };
static BASIC_TEST_CONTEXT mTest3 = { L"SysPrep0001", EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED };
static BASIC_TEST_CONTEXT mTest4 = { L"PlatformRecovery0001", EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED };
static BASIC_TEST_CONTEXT mTest5 = { EFI_DRIVER_ORDER_VARIABLE_NAME, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED };
static BASIC_TEST_CONTEXT mTest6 = { L"Driver0001", EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED };
STATIC BASIC_TEST_CONTEXT mTest1 = { EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_SUCCESS, 0, EFI_WRITE_PROTECTED, LoadOptionTypeMax };
STATIC BASIC_TEST_CONTEXT mTest2 = { EFI_SYS_PREP_ORDER_VARIABLE_NAME, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED, LoadOptionTypeMax };
STATIC BASIC_TEST_CONTEXT mTest3 = { EFI_DRIVER_ORDER_VARIABLE_NAME, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED, LoadOptionTypeMax };
STATIC BASIC_TEST_CONTEXT mTest4 = { L"SysPrep0001", EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED, LoadOptionTypeSysPrep };
STATIC BASIC_TEST_CONTEXT mTest5 = { L"PlatformRecovery0001", EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED, LoadOptionTypePlatformRecovery };
STATIC BASIC_TEST_CONTEXT mTest6 = { L"Driver0001", EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, NULL, EFI_NOT_FOUND, 0, EFI_WRITE_PROTECTED, LoadOptionTypeDriver };
STATIC EFI_DEVICE_PATH_PROTOCOL *mDevicePath = NULL;

/*
CleanUpTestContext
/**
Get the device path of the volume containing this application.
**/
STATIC
VOID
GetDevicePathOfThisApp (
VOID
)
{
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_HANDLE Handle;
EFI_HANDLE *HandleBuffer;
UINTN Index;
UINTN NumHandles;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SfProtocol;
EFI_STATUS Status;
EFI_FILE_PROTOCOL *FileHandle;
EFI_FILE_PROTOCOL *FileHandle2;

Status = EFI_SUCCESS;
SfProtocol = NULL;
NumHandles = 0;
HandleBuffer = NULL;
DevicePath = NULL;

// Locate all handles using the SFS protocol.
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiSimpleFileSystemProtocolGuid,
NULL,
&NumHandles,
&HandleBuffer
);

if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: failed to locate all handles using the Simple FS protocol (%r)\n", __FUNCTION__, Status));
goto CleanUp;
}

Cleans up after a test case. Free any allocated buffers if a test
takes the error exit.
// Search the handles to find one that is on a GPT partition.
for (Index = 0; Index < NumHandles; Index += 1) {
DevicePath = DevicePathFromHandle (HandleBuffer[Index]);
if (DevicePath == NULL) {
continue;
}

// Check if this is a block IO device path.
Status = gBS->LocateDevicePath (
&gEfiBlockIoProtocolGuid,
&DevicePath,
&Handle
);

if (EFI_ERROR (Status)) {
DevicePath = NULL;
continue;
}

Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiSimpleFileSystemProtocolGuid,
(VOID **)&SfProtocol
);

if (EFI_ERROR (Status)) {
DevicePath = NULL;
continue;
}

// Open the volume.
Status = SfProtocol->OpenVolume (SfProtocol, &FileHandle);
if (EFI_ERROR (Status)) {
DevicePath = NULL;
continue;
}

// Check if this app is present.
Status = FileHandle->Open (FileHandle, &FileHandle2, UNIT_TEST_APP_FILENAME, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR (Status)) {
Status = FileHandleClose (FileHandle);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Error closing Vol Handle: %r\n", __FUNCTION__, Status));
}

DevicePath = NULL;
continue;
} else {
Status = FileHandleClose (FileHandle2);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Error closing Vol Handle: %r\n", __FUNCTION__, Status));
}

break;
}
}

CleanUp:
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}

if (DevicePath != NULL) {
mDevicePath = DevicePath;
}
}

/*
CleanUpTestContext
Cleans up after a test case. Free any allocated buffers if a test
takes the error exit.
*/
STATIC
VOID
Expand All @@ -86,10 +198,9 @@ CleanUpTestContext (
}

/*
OsIndicationsSupport testing
OsIndicationsSupport testing
*/
static
STATIC
UNIT_TEST_STATUS
EFIAPI
OsIndicationsSupportTest (
Expand Down Expand Up @@ -144,21 +255,21 @@ OsIndicationsSupportTest (
}

/*
SysPrep testing
SysPrep testing
*/
static
STATIC
UNIT_TEST_STATUS
EFIAPI
VariableLockedTestTest (
IN UNIT_TEST_CONTEXT Context
)
{
BASIC_TEST_CONTEXT *Btc;
EFI_STATUS Status;
UINTN DataSize;
UINT32 Attributes;
UINT64 Data = 0x1122334455667788;
BASIC_TEST_CONTEXT *Btc;
EFI_STATUS Status;
UINTN DataSize;
UINT32 Attributes;
UINT64 Data = 0x1122334455667788;
EFI_BOOT_MANAGER_LOAD_OPTION Option;

Btc = (BASIC_TEST_CONTEXT *)Context;

Expand All @@ -174,6 +285,31 @@ VariableLockedTestTest (
UT_LOG_INFO ("\nGetVariable of %s. Return code %r, expected %r\n", Btc->TestName, Status, Btc->ExpectedStatus1a);
UT_ASSERT_STATUS_EQUAL (Status, Btc->ExpectedStatus1a);

if (Btc->OptionType < LoadOptionTypeMax) {
if (mDevicePath == NULL) {
UT_LOG_ERROR ("Could not locate device path of the volume containing this application\n");
UT_ASSERT_NOT_NULL (mDevicePath);
}

Status = EfiBootManagerInitializeLoadOption (
&Option,
1,
Btc->OptionType,
0,
L"Load Option Variable",
mDevicePath,
NULL,
0
);
UT_ASSERT_NOT_EFI_ERROR (Status);

Status = EfiBootManagerLoadOptionToVariable (&Option);
UT_LOG_INFO ("\nEfiBootManagerLoadOptionToVariable of %s. Return code %r, expected %r\n", Btc->TestName, Status, Btc->ExpectedStatus2);
UT_ASSERT_STATUS_EQUAL (Status, Btc->ExpectedStatus2);

return UNIT_TEST_PASSED;
}

DataSize = sizeof (Data);

Btc->VariableDeleteName = Btc->TestName;
Expand Down Expand Up @@ -240,11 +376,14 @@ BootAuditTestAppEntry (
// -----------Suite-----------Description-------------Class-------------------Test Function-------------Pre---Clean-Context
AddTestCase (BootAuditTests, "OsIndicationsSupport", "OsIndicationsSupport", OsIndicationsSupportTest, NULL, CleanUpTestContext, &mTest1);
AddTestCase (BootAuditTests, "SysPrepOrder", "Sysprep", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest2);
AddTestCase (BootAuditTests, "SysPrep0001", "Sysprep", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest3);
AddTestCase (BootAuditTests, "PlatformRecovery0001", "PlatformRecovery", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest4);
AddTestCase (BootAuditTests, "DriverOrder", "Driver", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest5);
AddTestCase (BootAuditTests, "DriverOrder", "Driver", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest3);
AddTestCase (BootAuditTests, "SysPrep0001", "Sysprep", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest4);
AddTestCase (BootAuditTests, "PlatformRecovery0001", "PlatformRecovery", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest5);
AddTestCase (BootAuditTests, "Driver0001", "Driver", VariableLockedTestTest, NULL, CleanUpTestContext, &mTest6);

// Store the device path associated with this app in a global for use when setting SysPrep0001, PlatformRecovery0001, and Driver0001.
GetDevicePathOfThisApp ();

//
// Execute the tests.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,16 @@
BaseLib
BaseMemoryLib
DebugLib
DevicePathLib
FileHandleLib
PrintLib
UefiApplicationEntryPoint
UefiBootManagerLib
UefiBootServicesTableLib
UefiLib
UefiRuntimeServicesTableLib
UnitTestLib
UnitTestLib

[Protocols]
gEfiBlockIoProtocolGuid
gEfiSimpleFileSystemProtocolGuid
6 changes: 6 additions & 0 deletions UefiTestingPkg/UefiTestingPkg.dsc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
MemoryTypeInformationChangeLib|MdeModulePkg/Library/MemoryTypeInformationChangeLibNull/MemoryTypeInformationChangeLibNull.inf

PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
Expand Down

0 comments on commit 8502050

Please sign in to comment.