MdeModulePkg/Core/Dxe: limit FwVol encapsulation section recursion

The DXE Core sets up a protocol notify function in its entry point, for
instances of the Firmware Volume Block2 Protocol:

  DxeMain()           [DxeMain/DxeMain.c]
    FwVolDriverInit() [FwVol/FwVol.c]

Assume that a 3rd party UEFI driver or application installs an FVB
instance, with crafted contents. The notification function runs:

  NotifyFwVolBlock() [FwVol/FwVol.c]

installing an instance of the Firmware Volume 2 Protocol on the handle.

(Alternatively, assume that a 3rd party application calls
gDS->ProcessFirmwareVolume(), which may also produce a Firmware Volume 2
Protocol instance.)

The EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadSection() member performs "a
depth-first, left-to-right search algorithm through all sections found in
the specified file" (quoting the PI spec), as follows:

  FvReadFileSection()   [FwVol/FwVolRead.c]
    GetSection()        [SectionExtraction/CoreSectionExtraction.c]
      FindChildNode()   [SectionExtraction/CoreSectionExtraction.c]
        FindChildNode() // recursive call

FindChildNode() is called recursively for encapsulation sections.

Currently this recursion is not limited. Introduce a new PCD
(fixed-at-build, or patchable-in-module), and make FindChildNode() track
the section nesting depth against that PCD.

Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1743
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20201119105340.16225-3-lersek@redhat.com>
This commit is contained in:
Laszlo Ersek
2020-11-19 11:53:40 +01:00
committed by mergify[bot]
parent b9bdfc7285
commit 47343af304
4 changed files with 44 additions and 2 deletions

View File

@ -955,6 +955,9 @@ CreateChildNode (
This is an in/out parameter and it is 1-based,
to deal with recursions.
@param SectionDefinitionGuid Guid of section definition
@param Depth Nesting depth of encapsulation sections.
Callers different from FindChildNode() are
responsible for passing in a zero Depth.
@param FoundChild Output indicating the child node that is found.
@param FoundStream Output indicating which section stream the child
was found in. If this stream was generated as a
@ -968,6 +971,9 @@ CreateChildNode (
@retval EFI_NOT_FOUND Requested child node does not exist.
@retval EFI_PROTOCOL_ERROR a required GUIDED section extraction protocol
does not exist
@retval EFI_ABORTED Recursion aborted because Depth has been
greater than or equal to
PcdFwVolDxeMaxEncapsulationDepth.
**/
EFI_STATUS
@ -976,6 +982,7 @@ FindChildNode (
IN EFI_SECTION_TYPE SearchType,
IN OUT UINTN *SectionInstance,
IN EFI_GUID *SectionDefinitionGuid,
IN UINT32 Depth,
OUT CORE_SECTION_CHILD_NODE **FoundChild,
OUT CORE_SECTION_STREAM_NODE **FoundStream,
OUT UINT32 *AuthenticationStatus
@ -990,6 +997,10 @@ FindChildNode (
ASSERT (*SectionInstance > 0);
if (Depth >= PcdGet32 (PcdFwVolDxeMaxEncapsulationDepth)) {
return EFI_ABORTED;
}
CurrentChildNode = NULL;
ErrorStatus = EFI_NOT_FOUND;
@ -1053,6 +1064,7 @@ FindChildNode (
SearchType,
SectionInstance,
SectionDefinitionGuid,
Depth + 1,
&RecursedChildNode,
&RecursedFoundStream,
AuthenticationStatus
@ -1067,9 +1079,17 @@ FindChildNode (
*FoundStream = RecursedFoundStream;
return EFI_SUCCESS;
} else {
if (Status == EFI_ABORTED) {
//
// If the recursive call was aborted due to nesting depth, stop
// looking for the requested child node. The skipped subtree could
// throw off the instance counting.
//
return Status;
}
//
// If the status is not EFI_SUCCESS, just save the error code and
// continue to find the request child node in the rest stream.
// Save the error code and continue to find the requested child node in
// the rest of the stream.
//
ErrorStatus = Status;
}
@ -1272,11 +1292,20 @@ GetSection (
*SectionType,
&Instance,
SectionDefinitionGuid,
0, // encapsulation depth
&ChildNode,
&ChildStreamNode,
&ExtractedAuthenticationStatus
);
if (EFI_ERROR (Status)) {
if (Status == EFI_ABORTED) {
DEBUG ((DEBUG_ERROR, "%a: recursion aborted due to nesting depth\n",
__FUNCTION__));
//
// Map "aborted" to "not found".
//
Status = EFI_NOT_FOUND;
}
goto GetSection_Done;
}