OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcStorageLib.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16#include <Guid/FileInfo.h>
17#include <Protocol/SimpleFileSystem.h>
18
19#include <Library/BaseLib.h>
20#include <Library/BaseMemoryLib.h>
21#include <Library/DebugLib.h>
22#include <Library/DevicePathLib.h>
23#include <Library/MemoryAllocationLib.h>
25#include <Library/OcStringLib.h>
27#include <Library/UefiBootServicesTableLib.h>
28
29OC_STRUCTORS (OC_STORAGE_VAULT_HASH, ())
30OC_MAP_STRUCTORS (OC_STORAGE_VAULT_FILES)
31OC_STRUCTORS (OC_STORAGE_VAULT, ())
32
33#pragma pack(push, 1)
34
35typedef PACKED struct {
36 VENDOR_DEFINED_DEVICE_PATH Vendor;
37 EFI_DEVICE_PATH_PROTOCOL End;
39
40typedef PACKED struct {
41 VENDOR_DEFINED_DEVICE_PATH Vendor;
42 VENDOR_DEFINED_DEVICE_PATH VendorFile;
43 EFI_DEVICE_PATH_PROTOCOL End;
45
46#pragma pack(pop)
47
48//
49// We do not want to expose these for the time being!.
50//
51
52#define INTERNAL_STORAGE_GUID \
53 { 0x33B5C65A, 0x5B82, 0x403D, {0x87, 0xA5, 0xD4, 0x67, 0x62, 0x50, 0xEC, 0x59} }
54
55#define INTERNAL_STORAGE_FILE_GUID \
56 { 0x1237EC17, 0xD3CE, 0x401D, {0xA8, 0x41, 0xB1, 0xD8, 0x18, 0xF8, 0xAF, 0x1A} }
57
58STATIC
61 .Vendor = {
62 .Header = {
63 .Type = HARDWARE_DEVICE_PATH,
64 .SubType = HW_VENDOR_DP,
65 .Length = { sizeof (VENDOR_DEFINED_DEVICE_PATH), 0 }
66 },
68 },
69 .End = {
70 .Type = END_DEVICE_PATH_TYPE,
71 .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
72 .Length = { END_DEVICE_PATH_LENGTH, 0 }
73 }
74};
75
76STATIC
79 .Vendor = {
80 .Header = {
81 .Type = HARDWARE_DEVICE_PATH,
82 .SubType = HW_VENDOR_DP,
83 .Length = { sizeof (VENDOR_DEFINED_DEVICE_PATH), 0 }
84 },
86 },
87 .VendorFile = {
88 .Header = {
89 .Type = HARDWARE_DEVICE_PATH,
90 .SubType = HW_VENDOR_DP,
91 .Length = { sizeof (VENDOR_DEFINED_DEVICE_PATH), 0 }
92 },
94 },
95 .End = {
96 .Type = END_DEVICE_PATH_TYPE,
97 .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
98 .Length = { END_DEVICE_PATH_LENGTH, 0 }
99 }
100};
101
102STATIC
105
109STATIC
112 OC_SCHEMA_MAP_IN ("Files", OC_STORAGE_VAULT, Files, &mVaultFilesSchema),
113 OC_SCHEMA_INTEGER_IN ("Version", OC_STORAGE_VAULT, Version),
114};
115
116STATIC
121
122STATIC
123EFI_STATUS
125 IN OUT OC_STORAGE_CONTEXT *Context,
126 IN VOID *Vault OPTIONAL,
127 IN UINT32 VaultSize,
128 IN OC_RSA_PUBLIC_KEY *StorageKey OPTIONAL,
129 IN VOID *Signature OPTIONAL,
130 IN UINT32 SignatureSize OPTIONAL
131 )
132{
133 if ((Signature != NULL) && (Vault == NULL)) {
134 DEBUG ((DEBUG_ERROR, "OCST: Missing vault with signature\n"));
135 return EFI_SECURITY_VIOLATION;
136 }
137
138 if (Vault == NULL) {
139 DEBUG ((DEBUG_INFO, "OCST: Missing vault data, ignoring...\n"));
140 return EFI_SUCCESS;
141 }
142
143 if (Signature != NULL) {
144 ASSERT (StorageKey != NULL);
145
146 if (!RsaVerifySigDataFromKeyDynalloc (StorageKey, Signature, SignatureSize, Vault, VaultSize, OcSigHashTypeSha256)) {
147 DEBUG ((DEBUG_ERROR, "OCST: Invalid vault signature\n"));
148 return EFI_SECURITY_VIOLATION;
149 }
150 }
151
152 OC_STORAGE_VAULT_CONSTRUCT (&Context->Vault, sizeof (Context->Vault));
153 if (!ParseSerialized (&Context->Vault, &mVaultSchema, Vault, VaultSize, NULL)) {
154 OC_STORAGE_VAULT_DESTRUCT (&Context->Vault, sizeof (Context->Vault));
155 DEBUG ((DEBUG_ERROR, "OCST: Invalid vault data\n"));
156 return EFI_INVALID_PARAMETER;
157 }
158
159 if (Context->Vault.Version != OC_STORAGE_VAULT_VERSION) {
160 OC_STORAGE_VAULT_DESTRUCT (&Context->Vault, sizeof (Context->Vault));
161 DEBUG ((
162 DEBUG_ERROR,
163 "OCST: Unsupported vault data version %u vs %u\n",
164 Context->Vault.Version,
166 ));
167 return EFI_UNSUPPORTED;
168 }
169
170 Context->HasVault = TRUE;
171
172 return EFI_SUCCESS;
173}
174
175STATIC
176UINT8 *
178 IN OUT OC_STORAGE_CONTEXT *Context,
179 IN CONST CHAR16 *Filename
180 )
181{
182 UINT32 Index;
183 UINTN StrIndex;
184 CHAR8 *VaultFilePath;
185 UINTN FilenameSize;
186
187 if (!Context->HasVault) {
188 return NULL;
189 }
190
191 FilenameSize = StrLen (Filename) + 1;
192
193 for (Index = 0; Index < Context->Vault.Files.Count; ++Index) {
194 if (Context->Vault.Files.Keys[Index]->Size != (UINT32)FilenameSize) {
195 continue;
196 }
197
198 VaultFilePath = OC_BLOB_GET (Context->Vault.Files.Keys[Index]);
199
200 for (StrIndex = 0; StrIndex < FilenameSize; ++StrIndex) {
201 if (Filename[StrIndex] != VaultFilePath[StrIndex]) {
202 break;
203 }
204 }
205
206 if (StrIndex == FilenameSize) {
207 return &Context->Vault.Files.Values[Index]->Hash[0];
208 }
209 }
210
211 return NULL;
212}
213
214EFI_STATUS
216 OUT OC_STORAGE_CONTEXT *Context,
217 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
218 IN EFI_HANDLE StorageHandle OPTIONAL,
219 IN EFI_DEVICE_PATH_PROTOCOL *StoragePath OPTIONAL,
220 IN CONST CHAR16 *StorageRoot,
221 IN OC_RSA_PUBLIC_KEY *StorageKey OPTIONAL
222 )
223{
224 EFI_STATUS Status;
225 EFI_FILE_PROTOCOL *RootVolume;
226 VOID *Vault;
227 VOID *Signature;
228 UINT32 DataSize;
229 UINT32 SignatureSize;
230
231 ASSERT (Context != NULL);
232 ASSERT (FileSystem != NULL);
233 ASSERT (StorageRoot != NULL);
234
235 ZeroMem (Context, sizeof (*Context));
236
237 Context->FileSystem = FileSystem;
238
239 Status = FileSystem->OpenVolume (FileSystem, &RootVolume);
240 if (EFI_ERROR (Status)) {
241 DEBUG ((DEBUG_INFO, "OCST: FileSystem volume cannot be opened - %r\n", Status));
242 return Status;
243 }
244
245 Status = OcSafeFileOpen (
246 RootVolume,
247 &Context->Storage,
248 (CHAR16 *)StorageRoot,
249 EFI_FILE_MODE_READ,
250 0
251 );
252
253 RootVolume->Close (RootVolume);
254
255 if (EFI_ERROR (Status)) {
256 DEBUG ((DEBUG_INFO, "OCST: Directory %s cannot be opened - %r\n", StorageRoot, Status));
257 return Status;
258 }
259
260 SignatureSize = 0;
261
262 if (StorageKey) {
264 Context,
266 &SignatureSize
267 );
268
269 if (Signature == NULL) {
270 DEBUG ((DEBUG_ERROR, "OCS: Missing vault signature\n"));
271 OcStorageFree (Context);
272 return EFI_SECURITY_VIOLATION;
273 }
274 } else {
275 Signature = NULL;
276 }
277
278 DataSize = 0;
280 Context,
282 &DataSize
283 );
284
285 Status = OcStorageInitializeVault (Context, Vault, DataSize, StorageKey, Signature, SignatureSize);
286
287 if (EFI_ERROR (Status)) {
288 DEBUG ((DEBUG_INFO, "OCST: Vault init failure %p (%u) - %r\n", Vault, DataSize, Status));
289 }
290
291 gBS->InstallProtocolInterface (
292 &Context->DummyStorageHandle,
294 EFI_NATIVE_INTERFACE,
296 );
297 Context->StorageHandle = StorageHandle;
298 Context->StoragePath = StoragePath;
299 Context->StorageRoot = StorageRoot;
300 Context->DummyDevicePath = &mDummyBootDeviceFilePath.Vendor.Header;
301 Context->DummyFilePath = &mDummyBootDeviceFilePath.VendorFile.Header;
302
303 if (Signature != NULL) {
304 FreePool (Signature);
305 }
306
307 if (Vault != NULL) {
308 FreePool (Vault);
309 }
310
311 return Status;
312}
313
314VOID
316 IN OUT OC_STORAGE_CONTEXT *Context
317 )
318{
319 if (Context->DummyStorageHandle != NULL) {
320 gBS->UninstallProtocolInterface (
321 Context->DummyStorageHandle,
324 );
325 Context->DummyStorageHandle = NULL;
326 }
327
328 if (Context->Storage != NULL) {
329 Context->Storage->Close (Context->Storage);
330 Context->Storage = NULL;
331 }
332
333 if (Context->HasVault) {
334 OC_STORAGE_VAULT_DESTRUCT (&Context->Vault, sizeof (Context->Vault));
335 Context->HasVault = FALSE;
336 }
337}
338
339BOOLEAN
341 IN OC_STORAGE_CONTEXT *Context,
342 IN CONST CHAR16 *FilePath
343 )
344{
345 EFI_STATUS Status;
346 EFI_FILE_PROTOCOL *File;
347 UINT8 *VaultDigest;
348
349 //
350 // Using this API with empty filename is also not allowed.
351 //
352 ASSERT (Context != NULL);
353 ASSERT (FilePath != NULL);
354 ASSERT (StrLen (FilePath) > 0);
355
356 VaultDigest = OcStorageGetDigest (Context, FilePath);
357
358 if (VaultDigest != NULL) {
359 return TRUE;
360 }
361
362 if (Context->Storage == NULL) {
363 return FALSE;
364 }
365
366 Status = OcSafeFileOpen (
367 Context->Storage,
368 &File,
369 (CHAR16 *)FilePath,
370 EFI_FILE_MODE_READ,
371 0
372 );
373
374 if (!EFI_ERROR (Status)) {
375 File->Close (File);
376 return TRUE;
377 }
378
379 return FALSE;
380}
381
382VOID *
384 IN OC_STORAGE_CONTEXT *Context,
385 IN CONST CHAR16 *FilePath,
386 OUT UINT32 *FileSize OPTIONAL
387 )
388{
389 EFI_STATUS Status;
390 EFI_FILE_PROTOCOL *File;
391 UINT32 Size;
392 UINT8 *FileBuffer;
393 UINT8 *VaultDigest;
394 UINT8 FileDigest[SHA256_DIGEST_SIZE];
395
396 //
397 // Using this API with empty filename is also not allowed.
398 //
399 ASSERT (Context != NULL);
400 ASSERT (FilePath != NULL);
401 ASSERT (StrLen (FilePath) > 0);
402
403 VaultDigest = OcStorageGetDigest (Context, FilePath);
404
405 if (Context->HasVault && (VaultDigest == NULL)) {
406 DEBUG ((DEBUG_ERROR, "OCST: Aborting %s file access not present in vault\n", FilePath));
407 return NULL;
408 }
409
410 if (Context->Storage == NULL) {
411 //
412 // TODO: expand support for other contexts.
413 //
414 return NULL;
415 }
416
417 Status = OcSafeFileOpen (
418 Context->Storage,
419 &File,
420 (CHAR16 *)FilePath,
421 EFI_FILE_MODE_READ,
422 0
423 );
424
425 if (EFI_ERROR (Status)) {
426 return NULL;
427 }
428
429 Status = OcGetFileSize (File, &Size);
430 if (EFI_ERROR (Status) || (Size >= MAX_UINT32 - 1)) {
431 File->Close (File);
432 return NULL;
433 }
434
435 FileBuffer = AllocatePool (Size + 2);
436 if (FileBuffer == NULL) {
437 File->Close (File);
438 return NULL;
439 }
440
441 Status = OcGetFileData (File, 0, Size, FileBuffer);
442 File->Close (File);
443 if (EFI_ERROR (Status)) {
444 FreePool (FileBuffer);
445 return NULL;
446 }
447
448 if (VaultDigest != 0) {
449 Sha256 (FileDigest, FileBuffer, Size);
450 if (CompareMem (FileDigest, VaultDigest, SHA256_DIGEST_SIZE) != 0) {
451 DEBUG ((DEBUG_ERROR, "OCST: Aborting corrupted %s file access\n", FilePath));
452 FreePool (FileBuffer);
453 return NULL;
454 }
455 }
456
457 FileBuffer[Size] = 0;
458 FileBuffer[Size + 1] = 0;
459
460 if (FileSize != NULL) {
461 *FileSize = Size;
462 }
463
464 return FileBuffer;
465}
466
467EFI_STATUS
469 IN OC_STORAGE_CONTEXT *Context,
470 IN CONST CHAR16 *FilePath,
471 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath OPTIONAL,
472 OUT EFI_HANDLE *StorageHandle OPTIONAL,
473 OUT EFI_DEVICE_PATH_PROTOCOL **StoragePath OPTIONAL,
474 IN BOOLEAN RealPath
475 )
476{
477 CHAR16 *FullPath;
478 UINTN RootLength;
479 UINTN FileSize;
480
481 if ( RealPath
482 && (Context->StorageHandle != NULL)
483 && (Context->StorageRoot != NULL)
484 && (Context->StoragePath != NULL))
485 {
486 //
487 // Set the storage handle right away.
488 //
489 *StorageHandle = Context->StorageHandle;
490
491 //
492 // Prepare file path.
493 //
494 RootLength = StrLen (Context->StorageRoot);
495 FileSize = StrSize (FilePath);
496 FullPath = AllocatePool (RootLength * sizeof (CHAR16) + sizeof (CHAR16) + FileSize);
497
498 if (FullPath == NULL) {
499 return EFI_OUT_OF_RESOURCES;
500 }
501
502 CopyMem (&FullPath[0], Context->StorageRoot, RootLength * sizeof (CHAR16));
503 FullPath[RootLength] = '\\';
504 CopyMem (&FullPath[RootLength + 1], FilePath, FileSize);
505
506 //
507 // Set joint device path.
508 //
509 *DevicePath = AppendFileNameDevicePath (Context->StoragePath, FullPath);
510 if (*DevicePath == NULL) {
511 FreePool (FullPath);
512 return EFI_OUT_OF_RESOURCES;
513 }
514
515 //
516 // Set onstorage path.
517 //
518 *StoragePath = FileDevicePath (NULL, FullPath);
519 if (*StoragePath == NULL) {
520 FreePool (*DevicePath);
521 FreePool (FullPath);
522 return EFI_OUT_OF_RESOURCES;
523 }
524
525 return EFI_SUCCESS;
526 }
527
528 *StorageHandle = Context->DummyStorageHandle;
529
530 *DevicePath = DuplicateDevicePath (Context->DummyDevicePath);
531 if (*DevicePath == NULL) {
532 return EFI_OUT_OF_RESOURCES;
533 }
534
535 *StoragePath = DuplicateDevicePath (Context->DummyFilePath);
536 if (*StoragePath == NULL) {
537 FreePool (*DevicePath);
538 return EFI_OUT_OF_RESOURCES;
539 }
540
541 return EFI_SUCCESS;
542}
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
UINT32 Version
UINT8 Signature[8]
Definition BiosId.h:67
DMG_FILEPATH_DEVICE_PATH FilePath
DMG_SIZE_DEVICE_PATH Size
EFI_BOOT_SERVICES * gBS
#define SHA256_DIGEST_SIZE
Definition OcCryptoLib.h:45
@ OcSigHashTypeSha256
VOID Sha256(UINT8 *Hash, CONST UINT8 *Data, UINTN Len)
BOOLEAN RsaVerifySigDataFromKeyDynalloc(IN CONST OC_RSA_PUBLIC_KEY *Key, IN CONST UINT8 *Signature, IN UINTN SignatureSize, IN CONST UINT8 *Data, IN UINTN DataSize, IN OC_SIG_HASH_TYPE Algorithm)
EFI_DEVICE_PATH_PROTOCOL * AppendFileNameDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CHAR16 *FileName)
EFI_STATUS OcGetFileSize(IN EFI_FILE_PROTOCOL *File, OUT UINT32 *Size)
EFI_STATUS OcGetFileData(IN EFI_FILE_PROTOCOL *File, IN UINT32 Position, IN UINT32 Size, OUT UINT8 *Buffer)
EFI_STATUS OcSafeFileOpen(IN CONST EFI_FILE_PROTOCOL *Directory, OUT EFI_FILE_PROTOCOL **NewHandle, IN CONST CHAR16 *FileName, IN CONST UINT64 OpenMode, IN CONST UINT64 Attributes)
Definition OpenFile.c:29
#define OC_SCHEMA_MAP_IN(Name, Type, Field, ChildSchema)
#define OC_SCHEMA_DATAF(Name, Type)
BOOLEAN ParseSerialized(OUT VOID *Serialized, IN OC_SCHEMA_INFO *RootSchema, IN VOID *PlistBuffer, IN UINT32 PlistSize, IN OUT UINT32 *ErrorCount OPTIONAL)
#define OC_SCHEMA_INTEGER_IN(Name, Type, Field)
STATIC EFI_STATUS OcStorageInitializeVault(IN OUT OC_STORAGE_CONTEXT *Context, IN VOID *Vault OPTIONAL, IN UINT32 VaultSize, IN OC_RSA_PUBLIC_KEY *StorageKey OPTIONAL, IN VOID *Signature OPTIONAL, IN UINT32 SignatureSize OPTIONAL)
BOOLEAN OcStorageExistsFileUnicode(IN OC_STORAGE_CONTEXT *Context, IN CONST CHAR16 *FilePath)
VENDOR_DEFINED_DEVICE_PATH VendorFile
STATIC OC_SCHEMA_INFO mVaultSchema
#define INTERNAL_STORAGE_GUID
PACKED struct @101 DUMMY_BOOT_DEVICE_FILE_PATH
EFI_STATUS OcStorageInitFromFs(OUT OC_STORAGE_CONTEXT *Context, IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem, IN EFI_HANDLE StorageHandle OPTIONAL, IN EFI_DEVICE_PATH_PROTOCOL *StoragePath OPTIONAL, IN CONST CHAR16 *StorageRoot, IN OC_RSA_PUBLIC_KEY *StorageKey OPTIONAL)
PACKED struct @100 DUMMY_BOOT_DEVICE_PATH
VOID * OcStorageReadFileUnicode(IN OC_STORAGE_CONTEXT *Context, IN CONST CHAR16 *FilePath, OUT UINT32 *FileSize OPTIONAL)
#define INTERNAL_STORAGE_FILE_GUID
STATIC UINT8 * OcStorageGetDigest(IN OUT OC_STORAGE_CONTEXT *Context, IN CONST CHAR16 *Filename)
STATIC OC_SCHEMA mVaultNodesSchema[]
STATIC DUMMY_BOOT_DEVICE_PATH mDummyBootDevicePath
EFI_DEVICE_PATH_PROTOCOL End
STATIC OC_SCHEMA mVaultFilesSchema
VOID OcStorageFree(IN OUT OC_STORAGE_CONTEXT *Context)
VENDOR_DEFINED_DEVICE_PATH Vendor
STATIC DUMMY_BOOT_DEVICE_FILE_PATH mDummyBootDeviceFilePath
EFI_STATUS OcStorageGetInfo(IN OC_STORAGE_CONTEXT *Context, IN CONST CHAR16 *FilePath, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath OPTIONAL, OUT EFI_HANDLE *StorageHandle OPTIONAL, OUT EFI_DEVICE_PATH_PROTOCOL **StoragePath OPTIONAL, IN BOOLEAN RealPath)
#define OC_STORAGE_VAULT_PATH
#define OC_STORAGE_VAULT_VERSION
#define OC_STORAGE_VAULT_SIGNATURE_PATH
#define OC_STRUCTORS(Name, Destructor)
#define OC_MAP_STRUCTORS(Name)
#define OC_BLOB_GET(Blob)
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_GUID gEfiDevicePathProtocolGuid
#define ASSERT(x)
Definition coder.h:55