blob: 2e58794c3c704ce516818c74480f893e8fe5c395 [file] [log] [blame]
/** @file
Blob verifier library that uses SEV hashes table. The hashes table holds the
allowed hashes of the kernel, initrd, and cmdline blobs.
Copyright (C) 2021, IBM Corporation
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseCryptLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/BlobVerifierLib.h>
/**
The SEV Hashes table must be in encrypted memory and has the table
and its entries described by
<GUID>|UINT16 <len>|<data>
With the whole table GUID being 9438d606-4f22-4cc9-b479-a793d411fd21
The current possible table entries are for the kernel, the initrd
and the cmdline:
4de79437-abd2-427f-b835-d5b172d2045b kernel
44baf731-3a2f-4bd7-9af1-41e29169781d initrd
97d02dd8-bd20-4c94-aa78-e7714d36ab2a cmdline
The size of the entry is used to identify the hash, but the
expectation is that it will be 32 bytes of SHA-256.
**/
#define SEV_HASH_TABLE_GUID \
(GUID) { 0x9438d606, 0x4f22, 0x4cc9, { 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21 } }
#define SEV_KERNEL_HASH_GUID \
(GUID) { 0x4de79437, 0xabd2, 0x427f, { 0xb8, 0x35, 0xd5, 0xb1, 0x72, 0xd2, 0x04, 0x5b } }
#define SEV_INITRD_HASH_GUID \
(GUID) { 0x44baf731, 0x3a2f, 0x4bd7, { 0x9a, 0xf1, 0x41, 0xe2, 0x91, 0x69, 0x78, 0x1d } }
#define SEV_CMDLINE_HASH_GUID \
(GUID) { 0x97d02dd8, 0xbd20, 0x4c94, { 0xaa, 0x78, 0xe7, 0x71, 0x4d, 0x36, 0xab, 0x2a } }
STATIC CONST EFI_GUID mSevKernelHashGuid = SEV_KERNEL_HASH_GUID;
STATIC CONST EFI_GUID mSevInitrdHashGuid = SEV_INITRD_HASH_GUID;
STATIC CONST EFI_GUID mSevCmdlineHashGuid = SEV_CMDLINE_HASH_GUID;
#pragma pack (1)
typedef struct {
GUID Guid;
UINT16 Len;
UINT8 Data[];
} HASH_TABLE;
#pragma pack ()
STATIC HASH_TABLE *mHashesTable;
STATIC UINT16 mHashesTableSize;
STATIC
CONST GUID *
FindBlobEntryGuid (
IN CONST CHAR16 *BlobName
)
{
if (StrCmp (BlobName, L"kernel") == 0) {
return &mSevKernelHashGuid;
} else if (StrCmp (BlobName, L"initrd") == 0) {
return &mSevInitrdHashGuid;
} else if (StrCmp (BlobName, L"cmdline") == 0) {
return &mSevCmdlineHashGuid;
} else {
return NULL;
}
}
/**
Verify blob from an external source.
@param[in] BlobName The name of the blob
@param[in] Buf The data of the blob
@param[in] BufSize The size of the blob in bytes
@retval EFI_SUCCESS The blob was verified successfully.
@retval EFI_ACCESS_DENIED The blob could not be verified, and therefore
should be considered non-secure.
**/
EFI_STATUS
EFIAPI
VerifyBlob (
IN CONST CHAR16 *BlobName,
IN CONST VOID *Buf,
IN UINT32 BufSize
)
{
CONST GUID *Guid;
INT32 Remaining;
HASH_TABLE *Entry;
if ((mHashesTable == NULL) || (mHashesTableSize == 0)) {
DEBUG ((
DEBUG_ERROR,
"%a: Verifier called but no hashes table discoverd in MEMFD\n",
__func__
));
return EFI_ACCESS_DENIED;
}
Guid = FindBlobEntryGuid (BlobName);
if (Guid == NULL) {
DEBUG ((
DEBUG_ERROR,
"%a: Unknown blob name \"%s\"\n",
__func__,
BlobName
));
return EFI_ACCESS_DENIED;
}
//
// Remaining is INT32 to catch underflow in case Entry->Len has a
// very high UINT16 value
//
for (Entry = mHashesTable, Remaining = mHashesTableSize;
Remaining >= sizeof *Entry && Remaining >= Entry->Len;
Remaining -= Entry->Len,
Entry = (HASH_TABLE *)((UINT8 *)Entry + Entry->Len))
{
UINTN EntrySize;
EFI_STATUS Status;
UINT8 Hash[SHA256_DIGEST_SIZE];
if (!CompareGuid (&Entry->Guid, Guid)) {
continue;
}
DEBUG ((DEBUG_INFO, "%a: Found GUID %g in table\n", __func__, Guid));
EntrySize = Entry->Len - sizeof Entry->Guid - sizeof Entry->Len;
if (EntrySize != SHA256_DIGEST_SIZE) {
DEBUG ((
DEBUG_ERROR,
"%a: Hash has the wrong size %d != %d\n",
__func__,
EntrySize,
SHA256_DIGEST_SIZE
));
return EFI_ACCESS_DENIED;
}
//
// Calculate the buffer's hash and verify that it is identical to the
// expected hash table entry
//
Sha256HashAll (Buf, BufSize, Hash);
if (CompareMem (Entry->Data, Hash, EntrySize) == 0) {
Status = EFI_SUCCESS;
DEBUG ((
DEBUG_INFO,
"%a: Hash comparison succeeded for \"%s\"\n",
__func__,
BlobName
));
} else {
Status = EFI_ACCESS_DENIED;
DEBUG ((
DEBUG_ERROR,
"%a: Hash comparison failed for \"%s\"\n",
__func__,
BlobName
));
}
return Status;
}
DEBUG ((
DEBUG_ERROR,
"%a: Hash GUID %g not found in table\n",
__func__,
Guid
));
return EFI_ACCESS_DENIED;
}
/**
Locate the SEV hashes table.
This function always returns success, even if the table can't be found. The
subsequent VerifyBlob calls will fail if no table was found.
@retval RETURN_SUCCESS The hashes table is set up correctly, or there is no
hashes table
**/
RETURN_STATUS
EFIAPI
BlobVerifierLibSevHashesConstructor (
VOID
)
{
HASH_TABLE *Ptr;
UINT32 Size;
mHashesTable = NULL;
mHashesTableSize = 0;
Ptr = (void *)(UINTN)FixedPcdGet64 (PcdQemuHashTableBase);
Size = FixedPcdGet32 (PcdQemuHashTableSize);
if ((Ptr == NULL) || (Size < sizeof *Ptr) ||
!CompareGuid (&Ptr->Guid, &SEV_HASH_TABLE_GUID) ||
(Ptr->Len < sizeof *Ptr) || (Ptr->Len > Size))
{
return RETURN_SUCCESS;
}
DEBUG ((
DEBUG_INFO,
"%a: Found injected hashes table in secure location\n",
__func__
));
mHashesTable = (HASH_TABLE *)Ptr->Data;
mHashesTableSize = Ptr->Len - sizeof Ptr->Guid - sizeof Ptr->Len;
DEBUG ((
DEBUG_VERBOSE,
"%a: mHashesTable=0x%p, Size=%u\n",
__func__,
mHashesTable,
mHashesTableSize
));
return RETURN_SUCCESS;
}