From 8d1a7ee22fc04d2106f08461415ee8bc9c68eee6 Mon Sep 17 00:00:00 2001 From: Oliver Steffen Date: Mon, 4 Nov 2024 12:40:12 +0100 Subject: [PATCH 1/2] OvmfPkg: Add a Fallback RNG (RH only) RH-Author: Oliver Steffen RH-MergeRequest: 104: OvmfPkg: Add a Fallback RNG (RH only) RH-Jira: RHEL-66236 RH-Acked-by: Gerd Hoffmann RH-Commit: [1/2] b222642bafac64922f5fc30abf56347fe4a849ed Since the pixiefail CVE fix, the network stack requires a random number generator. In case there is no hardware random number generator available, have the Platform Boot Manager install a pseudo RNG to ensure the network can be used. Signed-off-by: Oliver Steffen --- .../PlatformBootManagerLib/BdsPlatform.c | 6 + .../PlatformBootManagerLib/FallbackRng.c | 222 ++++++++++++++++++ .../PlatformBootManagerLib/FallbackRng.h | 20 ++ .../PlatformBootManagerLib.inf | 5 + 4 files changed, 253 insertions(+) create mode 100644 OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.c create mode 100644 OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.h diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c index 186401296a..70d648c7e3 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c @@ -14,6 +14,7 @@ #include #include +#include "FallbackRng.h" // // Global data @@ -446,6 +447,9 @@ PlatformBootManagerBeforeConsole ( // VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid, ConnectVirtioPciRng, NULL); + + FallbackRngCheckAndInstall (); + } @@ -1528,6 +1532,8 @@ PlatformBootManagerAfterConsole ( DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n")); + FallbackRngPrintWarning (); + if (PcdGetBool (PcdOvmfFlashVariablesEnable)) { DEBUG ((DEBUG_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars " "from disk since flash variables appear to be supported.\n")); diff --git a/OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.c b/OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.c new file mode 100644 index 0000000000..bba60e29d5 --- /dev/null +++ b/OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.c @@ -0,0 +1,222 @@ +/** @file + Copyright (C) 2024, Red Hat, Inc. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FallbackRng.h" + +typedef struct { + EFI_RNG_PROTOCOL Rng; + EFI_HANDLE Handle; +} FALLBACK_RNG_DEV; + +/** + Returns information about the random number generation implementation. + + @param[in] This A pointer to the EFI_RNG_PROTOCOL + instance. + @param[in,out] RNGAlgorithmListSize On input, the size in bytes of + RNGAlgorithmList. + On output with a return code of + EFI_SUCCESS, the size in bytes of the + data returned in RNGAlgorithmList. On + output with a return code of + EFI_BUFFER_TOO_SMALL, the size of + RNGAlgorithmList required to obtain the + list. + @param[out] RNGAlgorithmList A caller-allocated memory buffer filled + by the driver with one EFI_RNG_ALGORITHM + element for each supported RNG algorithm. + The list must not change across multiple + calls to the same driver. The first + algorithm in the list is the default + algorithm for the driver. + + @retval EFI_SUCCESS The RNG algorithm list was returned + successfully. + @retval EFI_UNSUPPORTED The services is not supported by this + driver. + @retval EFI_DEVICE_ERROR The list of algorithms could not be + retrieved due to a hardware or firmware + error. + @retval EFI_INVALID_PARAMETER One or more of the parameters are + incorrect. + @retval EFI_BUFFER_TOO_SMALL The buffer RNGAlgorithmList is too small + to hold the result. + +**/ +STATIC +EFI_STATUS +EFIAPI +FallbackRngGetInfo ( + IN EFI_RNG_PROTOCOL *This, + IN OUT UINTN *RNGAlgorithmListSize, + OUT EFI_RNG_ALGORITHM *RNGAlgorithmList + ) +{ + if ((This == NULL) || (RNGAlgorithmListSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*RNGAlgorithmListSize < sizeof (EFI_RNG_ALGORITHM)) { + *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM); + return EFI_BUFFER_TOO_SMALL; + } + + if (RNGAlgorithmList == NULL) { + return EFI_INVALID_PARAMETER; + } + + *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM); + CopyGuid (RNGAlgorithmList, &gEfiRngAlgorithmRaw); + + return EFI_SUCCESS; +} + +/** + Produces and returns an RNG value using either the default or specified RNG + algorithm. + + @param[in] This A pointer to the EFI_RNG_PROTOCOL + instance. + @param[in] RNGAlgorithm A pointer to the EFI_RNG_ALGORITHM that + identifies the RNG algorithm to use. May + be NULL in which case the function will + use its default RNG algorithm. + @param[in] RNGValueLength The length in bytes of the memory buffer + pointed to by RNGValue. The driver shall + return exactly this numbers of bytes. + @param[out] RNGValue A caller-allocated memory buffer filled + by the driver with the resulting RNG + value. + + @retval EFI_SUCCESS The RNG value was returned successfully. + @retval EFI_UNSUPPORTED The algorithm specified by RNGAlgorithm + is not supported by this driver. + @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due + to a hardware or firmware error. + @retval EFI_NOT_READY There is not enough random data available + to satisfy the length requested by + RNGValueLength. + @retval EFI_INVALID_PARAMETER RNGValue is NULL or RNGValueLength is + zero. + +**/ +STATIC +EFI_STATUS +EFIAPI +FallbackRngGetRNG ( + IN EFI_RNG_PROTOCOL *This, + IN EFI_RNG_ALGORITHM *RNGAlgorithm OPTIONAL, + IN UINTN RNGValueLength, + OUT UINT8 *RNGValue + ) +{ + UINT64 RandomData; + EFI_STATUS Status; + UINTN i; + + if ((This == NULL) || (RNGValueLength == 0) || (RNGValue == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // We only support the raw algorithm, so reject requests for anything else + // + if ((RNGAlgorithm != NULL) && + !CompareGuid (RNGAlgorithm, &gEfiRngAlgorithmRaw)) + { + return EFI_UNSUPPORTED; + } + + for (i = 0; i < RNGValueLength; ++i) { + if (i % 4 == 0) { + Status = GetRandomNumber64 (&RandomData); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +static FALLBACK_RNG_DEV Dev = { + .Rng.GetInfo = FallbackRngGetInfo, + .Rng.GetRNG = FallbackRngGetRNG, + .Handle = NULL, +}; + +EFI_STATUS +FallbackRngCheckAndInstall ( + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer = NULL; + UINTN HandleCount = 0; + + if (Dev.Handle != NULL) { + DEBUG ((DEBUG_INFO, "Fallback RNG already installed.\n")); + return EFI_ALREADY_STARTED; + } + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiRngProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + gBS->FreePool (HandleBuffer); + + if (Status == EFI_NOT_FOUND) { + HandleCount = 0; + } else if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error locating RNG protocol instances: %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "Found %u RNGs\n", HandleCount)); + + if (HandleCount == 0) { + // Install RNG + Status = gBS->InstallProtocolInterface ( + &Dev.Handle, + &gEfiRngProtocolGuid, + EFI_NATIVE_INTERFACE, + &Dev.Rng + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to install fallback RNG: %r\n", Status)); + return Status; + } + + gDS->Dispatch (); + } + + return EFI_SUCCESS; +} + +VOID +FallbackRngPrintWarning ( + ) +{ + if (Dev.Handle != NULL) { + Print (L"WARNING: Pseudo Random Number Generator in use - Pixiefail CVE not mitigated!\n"); + DEBUG ((DEBUG_WARN, "WARNING: Pseudo Random Number Generator in use - Pixiefail CVE not mitigated!\n")); + gBS->Stall (2000000); + } +} diff --git a/OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.h b/OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.h new file mode 100644 index 0000000000..77332bc51c --- /dev/null +++ b/OvmfPkg/Library/PlatformBootManagerLib/FallbackRng.h @@ -0,0 +1,20 @@ +/** @file + Copyright (C) 2024, Red Hat, Inc. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _FALLBACK_RNG_H_ +#define _FALLBACK_RNG_H_ + +#include +#include + +EFI_STATUS +FallbackRngCheckAndInstall ( + ); + +VOID +FallbackRngPrintWarning ( + ); + +#endif diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index c249a3cf1e..154b0b6c88 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -25,6 +25,8 @@ PlatformData.c QemuKernel.c BdsPlatform.h + FallbackRng.c + FallbackRng.h [Packages] MdePkg/MdePkg.dec @@ -56,6 +58,7 @@ PlatformBmPrintScLib Tcg2PhysicalPresenceLib XenPlatformLib + RngLib [Pcd] gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent @@ -78,9 +81,11 @@ gEfiDxeSmmReadyToLockProtocolGuid # PROTOCOL SOMETIMES_PRODUCED gEfiLoadedImageProtocolGuid # PROTOCOL SOMETIMES_PRODUCED gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiRngProtocolGuid # PROTOCOL SOMETIMES_PRODUCED [Guids] gEfiEndOfDxeEventGroupGuid gEfiGlobalVariableGuid gRootBridgesConnectedEventGroupGuid gUefiShellFileGuid + gEfiRngAlgorithmRaw -- 2.45.2