Skip to content

Improving error handing in Variable Smm#12670

Open
PaddyDeng-v wants to merge 2 commits into
tianocore:masterfrom
PaddyDeng-v:user/paddydeng/HardenVariableSmm
Open

Improving error handing in Variable Smm#12670
PaddyDeng-v wants to merge 2 commits into
tianocore:masterfrom
PaddyDeng-v:user/paddydeng/HardenVariableSmm

Conversation

@PaddyDeng-v

Copy link
Copy Markdown
Contributor

Description

This PR includes 2 commits that improves error handling in VariableSmm

  1. Gracefully fail in MmVariableServiceInitialize: Some platform may disable dead loop on assert. In this case, we should also abort the function in assert cases.
  2. Check mNvVariableCache before use in SmiVariableHandler
  • Breaking change?
    • Breaking change - Does this PR cause a break in build or boot behavior?
    • Examples: Does it add a new library class or move a module to a different repo.
  • Impacts security?
    • Security - Does this PR have a direct security impact?
    • Examples: Crypto algorithm change or buffer overflow fix.
  • Includes tests?
    • Tests - Does this PR include any explicit test code?
    • Examples: Unit tests or integration tests.

How This Was Tested

After apply both commits, the platform can still boot to OS. No error is happing.

Integration Instructions

N/A

Some platforms may disable `ASSERT_DEADLOOP_ENABLED` in
`PcdDebugPropertyMask`. In this case ASSERT won't hang the machine.
Replaced those simple ASSERT with proper error returning handling.

Signed-off-by: Paddy Deng (AMI US Holdings Inc) <v-dengpaddy@microsoft.com>
Some control flow in SmmVariableHandler rely on the global variable
mNvVariableCache. But without checking if its value is valid or not.
This commit adds several null guard before the handler accessing the
cache variable.

Signed-off-by: Paddy Deng (AMI US Holdings Inc) <v-dengpaddy@microsoft.com>
@PaddyDeng-v PaddyDeng-v force-pushed the user/paddydeng/HardenVariableSmm branch from 88d5d11 to 5b559c9 Compare June 12, 2026 11:58
@PaddyDeng-v PaddyDeng-v marked this pull request as ready for review June 12, 2026 11:59
&mSmmVarCheck
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PaddyDeng-v, I think you need to consider system-state cleanup since this is a behavior change. Previously, an assertion call either:

  • Did nothing
  • Triggered a breakpoint
  • Entered a deadloop

This change adds a new possibility to return partially through the initialization flow at various points to firmware execution.

If subsequent initialization fails, gEfiSmmVariableProtocolGuid should likely be uninstalled as it exposes MM variable services within the MM environment that would be in a "partially initialized" state.

For example, if gEfiSmmVariableProtocolGuid is installed successfully (Line 1179), but gEdkiiSmmVarCheckProtocolGuid installation fails (Line 1196), that means the call to register the variable SMI handler (Line 1237) is not executed. MM drivers (using gEfiSmmVariableProtocolGuid directly) might participate in a flow where they expect variables written from outside the MM environment (which relies on the SMI handler) and that is not available.

These types of dependencies can be established and broken down throughout initialization, but I think the simplest answer is that "if initialization fails, variable services are not available". So, interfaces in global databases (like the protocol database) are removed.

SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;
switch (SmmVariableFunctionHeader->Function) {
case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
if (mNvVariableCache == NULL) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mNvVariableCache is assigned in InitNonVolatileVariableStore() via VariableCommonInitialize(), which runs at the very top of MmVariableServiceInitialize. Since commit 1 now aborts before MmiHandlerRegister when that fails, the SMI handler should only ever be registered when mNvVariableCache is non-NULL, so these per-case NULL checks look unreachable in the normal flow. Are they guarding a specific scenario (e.g. a custom/downstream init ordering)? If so, a brief comment would help future readers; if not, they could be dropped, since commit 1 is the actual safeguard


if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
DEBUG ((DEBUG_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small consistency note: the new guards correctly set Status and goto EXIT (so ReturnStatus is written back), but the sibling buffer-size checks in these cases still return EFI_SUCCESS without setting ReturnStatus. Because the DXE caller reads SmmVariableFunctionHeader->ReturnStatus directly, that path can surface a stale value from the previous operation. Converting these to Status = EFI_INVALID_PARAMETER; goto EXIT; would make the handler consistent. (Pre-existing; optional, but you're already in these cases.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants