VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c

Last change on this file was 108794, checked in by vboxsync, 3 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 6.6 KB
Line 
1/** @file
2
3 Blob verifier library that uses SEV hashes table. The hashes table holds the
4 allowed hashes of the kernel, initrd, and cmdline blobs.
5
6 Copyright (C) 2021, IBM Corporation
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9**/
10
11#include <Library/BaseCryptLib.h>
12#include <Library/BaseLib.h>
13#include <Library/BaseMemoryLib.h>
14#include <Library/DebugLib.h>
15#include <Library/BlobVerifierLib.h>
16
17/**
18 The SEV Hashes table must be in encrypted memory and has the table
19 and its entries described by
20
21 <GUID>|UINT16 <len>|<data>
22
23 With the whole table GUID being 9438d606-4f22-4cc9-b479-a793d411fd21
24
25 The current possible table entries are for the kernel, the initrd
26 and the cmdline:
27
28 4de79437-abd2-427f-b835-d5b172d2045b kernel
29 44baf731-3a2f-4bd7-9af1-41e29169781d initrd
30 97d02dd8-bd20-4c94-aa78-e7714d36ab2a cmdline
31
32 The size of the entry is used to identify the hash, but the
33 expectation is that it will be 32 bytes of SHA-256.
34**/
35
36#define SEV_HASH_TABLE_GUID \
37 (GUID) { 0x9438d606, 0x4f22, 0x4cc9, { 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21 } }
38#define SEV_KERNEL_HASH_GUID \
39 (GUID) { 0x4de79437, 0xabd2, 0x427f, { 0xb8, 0x35, 0xd5, 0xb1, 0x72, 0xd2, 0x04, 0x5b } }
40#define SEV_INITRD_HASH_GUID \
41 (GUID) { 0x44baf731, 0x3a2f, 0x4bd7, { 0x9a, 0xf1, 0x41, 0xe2, 0x91, 0x69, 0x78, 0x1d } }
42#define SEV_CMDLINE_HASH_GUID \
43 (GUID) { 0x97d02dd8, 0xbd20, 0x4c94, { 0xaa, 0x78, 0xe7, 0x71, 0x4d, 0x36, 0xab, 0x2a } }
44
45STATIC CONST EFI_GUID mSevKernelHashGuid = SEV_KERNEL_HASH_GUID;
46STATIC CONST EFI_GUID mSevInitrdHashGuid = SEV_INITRD_HASH_GUID;
47STATIC CONST EFI_GUID mSevCmdlineHashGuid = SEV_CMDLINE_HASH_GUID;
48
49#pragma pack (1)
50typedef struct {
51 GUID Guid;
52 UINT16 Len;
53 UINT8 Data[];
54} HASH_TABLE;
55#pragma pack ()
56
57STATIC HASH_TABLE *mHashesTable;
58STATIC UINT16 mHashesTableSize;
59
60STATIC
61CONST GUID *
62FindBlobEntryGuid (
63 IN CONST CHAR16 *BlobName
64 )
65{
66 if (StrCmp (BlobName, L"kernel") == 0) {
67 return &mSevKernelHashGuid;
68 } else if (StrCmp (BlobName, L"initrd") == 0) {
69 return &mSevInitrdHashGuid;
70 } else if (StrCmp (BlobName, L"cmdline") == 0) {
71 return &mSevCmdlineHashGuid;
72 } else {
73 return NULL;
74 }
75}
76
77/**
78 Verify blob from an external source.
79
80 If a non-secure configuration is detected this function will enter a
81 dead loop to prevent a boot.
82
83 @param[in] BlobName The name of the blob
84 @param[in] Buf The data of the blob
85 @param[in] BufSize The size of the blob in bytes
86 @param[in] FetchStatus The status of the previous blob fetch
87
88 @retval EFI_SUCCESS The blob was verified successfully or was not
89 found in the hash table.
90 @retval EFI_ACCESS_DENIED Kernel hashes not supported, but the boot
91 can continue safely.
92**/
93EFI_STATUS
94EFIAPI
95VerifyBlob (
96 IN CONST CHAR16 *BlobName,
97 IN CONST VOID *Buf,
98 IN UINT32 BufSize,
99 IN EFI_STATUS FetchStatus
100 )
101{
102 CONST GUID *Guid;
103 INT32 Remaining;
104 HASH_TABLE *Entry;
105
106 // Enter a dead loop if the fetching of this blob
107 // failed. This prevents a malicious host from
108 // circumventing the following checks.
109 if (EFI_ERROR (FetchStatus)) {
110 DEBUG ((
111 DEBUG_ERROR,
112 "%a: Fetching blob failed.\n",
113 __func__
114 ));
115
116 CpuDeadLoop ();
117 }
118
119 if ((mHashesTable == NULL) || (mHashesTableSize == 0)) {
120 DEBUG ((
121 DEBUG_WARN,
122 "%a: Verifier called but no hashes table discoverd in MEMFD\n",
123 __func__
124 ));
125 return EFI_ACCESS_DENIED;
126 }
127
128 Guid = FindBlobEntryGuid (BlobName);
129 if (Guid == NULL) {
130 DEBUG ((
131 DEBUG_ERROR,
132 "%a: Unknown blob name \"%s\"\n",
133 __func__,
134 BlobName
135 ));
136
137 CpuDeadLoop ();
138 }
139
140 //
141 // Remaining is INT32 to catch underflow in case Entry->Len has a
142 // very high UINT16 value
143 //
144 for (Entry = mHashesTable, Remaining = mHashesTableSize;
145 Remaining >= sizeof *Entry && Remaining >= Entry->Len;
146 Remaining -= Entry->Len,
147 Entry = (HASH_TABLE *)((UINT8 *)Entry + Entry->Len))
148 {
149 UINTN EntrySize;
150 EFI_STATUS Status;
151 UINT8 Hash[SHA256_DIGEST_SIZE];
152
153 if (!CompareGuid (&Entry->Guid, Guid)) {
154 continue;
155 }
156
157 DEBUG ((DEBUG_INFO, "%a: Found GUID %g in table\n", __func__, Guid));
158
159 EntrySize = Entry->Len - sizeof Entry->Guid - sizeof Entry->Len;
160 if (EntrySize != SHA256_DIGEST_SIZE) {
161 DEBUG ((
162 DEBUG_WARN,
163 "%a: Hash has the wrong size %d != %d\n",
164 __func__,
165 EntrySize,
166 SHA256_DIGEST_SIZE
167 ));
168 return EFI_ACCESS_DENIED;
169 }
170
171 //
172 // Calculate the buffer's hash and verify that it is identical to the
173 // expected hash table entry
174 //
175 Sha256HashAll (Buf, BufSize, Hash);
176
177 if (CompareMem (Entry->Data, Hash, EntrySize) == 0) {
178 Status = EFI_SUCCESS;
179 DEBUG ((
180 DEBUG_INFO,
181 "%a: Hash comparison succeeded for \"%s\"\n",
182 __func__,
183 BlobName
184 ));
185 } else {
186 Status = EFI_ACCESS_DENIED;
187 DEBUG ((
188 DEBUG_ERROR,
189 "%a: Hash comparison failed for \"%s\"\n",
190 __func__,
191 BlobName
192 ));
193
194 CpuDeadLoop ();
195 }
196
197 return Status;
198 }
199
200 //
201 // If the GUID is not in the hash table, execution can still continue.
202 // This blob will not be measured, but at least one blob must be.
203 //
204 DEBUG ((
205 DEBUG_ERROR,
206 "%a: Hash GUID %g not found in table\n",
207 __func__,
208 Guid
209 ));
210 return EFI_SUCCESS;
211}
212
213/**
214 Locate the SEV hashes table.
215
216 This function always returns success, even if the table can't be found. The
217 subsequent VerifyBlob calls will fail if no table was found.
218
219 @retval RETURN_SUCCESS The hashes table is set up correctly, or there is no
220 hashes table
221**/
222RETURN_STATUS
223EFIAPI
224BlobVerifierLibSevHashesConstructor (
225 VOID
226 )
227{
228 HASH_TABLE *Ptr;
229 UINT32 Size;
230
231 mHashesTable = NULL;
232 mHashesTableSize = 0;
233
234 Ptr = (void *)(UINTN)FixedPcdGet64 (PcdQemuHashTableBase);
235 Size = FixedPcdGet32 (PcdQemuHashTableSize);
236
237 if ((Ptr == NULL) || (Size < sizeof *Ptr) ||
238 !CompareGuid (&Ptr->Guid, &SEV_HASH_TABLE_GUID) ||
239 (Ptr->Len < sizeof *Ptr) || (Ptr->Len > Size))
240 {
241 return RETURN_SUCCESS;
242 }
243
244 DEBUG ((
245 DEBUG_INFO,
246 "%a: Found injected hashes table in secure location\n",
247 __func__
248 ));
249
250 mHashesTable = (HASH_TABLE *)Ptr->Data;
251 mHashesTableSize = Ptr->Len - sizeof Ptr->Guid - sizeof Ptr->Len;
252
253 DEBUG ((
254 DEBUG_VERBOSE,
255 "%a: mHashesTable=0x%p, Size=%u\n",
256 __func__,
257 mHashesTable,
258 mHashesTableSize
259 ));
260
261 return RETURN_SUCCESS;
262}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette