VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/UefiVariableStoreImpl.cpp@ 91536

Last change on this file since 91536 was 91535, checked in by vboxsync, 3 years ago

Main/{NvramStore,UefiVariableStore}: Always retain/releas the variable store reference in every externally accessible API to make sure the variable store is flushed to the NVRAM when saving avoiding data loss, bugref:9580

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.5 KB
Line 
1/* $Id: UefiVariableStoreImpl.cpp 91535 2021-10-04 09:15:19Z vboxsync $ */
2/** @file
3 * VirtualBox COM NVRAM store class implementation
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_MAIN_UEFIVARIABLESTORE
19#include "LoggingNew.h"
20
21#include "UefiVariableStoreImpl.h"
22#include "NvramStoreImpl.h"
23#include "MachineImpl.h"
24
25#include "AutoStateDep.h"
26#include "AutoCaller.h"
27
28#include "TrustAnchorsAndCerts.h"
29
30#include <VBox/com/array.h>
31
32#include <iprt/cpp/utils.h>
33#include <iprt/efi.h>
34#include <iprt/file.h>
35#include <iprt/vfs.h>
36
37#include <iprt/formats/efi-varstore.h>
38#include <iprt/formats/efi-signature.h>
39
40// defines
41////////////////////////////////////////////////////////////////////////////////
42
43// globals
44////////////////////////////////////////////////////////////////////////////////
45
46/////////////////////////////////////////////////////////////////////////////
47// UefiVariableStore::Data structure
48/////////////////////////////////////////////////////////////////////////////
49
50struct UefiVariableStore::Data
51{
52 Data()
53 : pParent(NULL),
54 pMachine(NULL),
55 hVfsUefiVarStore(NIL_RTVFS)
56 { }
57
58 /** The NVRAM store owning this UEFI variable store intstance. */
59 NvramStore * const pParent;
60 /** The machine this UEFI variable store belongs to. */
61 Machine * const pMachine;
62 /** VFS handle to the UEFI variable store. */
63 RTVFS hVfsUefiVarStore;
64};
65
66// constructor / destructor
67////////////////////////////////////////////////////////////////////////////////
68
69DEFINE_EMPTY_CTOR_DTOR(UefiVariableStore)
70
71HRESULT UefiVariableStore::FinalConstruct()
72{
73 return BaseFinalConstruct();
74}
75
76void UefiVariableStore::FinalRelease()
77{
78 uninit();
79 BaseFinalRelease();
80}
81
82// public initializer/uninitializer for internal purposes only
83/////////////////////////////////////////////////////////////////////////////
84
85/**
86 * Initializes the UEFI variable store object.
87 *
88 * @returns COM result indicator.
89 * @param aParent The NVRAM store owning the UEFI NVRAM content.
90 * @param pMachine
91 */
92HRESULT UefiVariableStore::init(NvramStore *aParent, Machine *pMachine)
93{
94 LogFlowThisFuncEnter();
95 LogFlowThisFunc(("aParent: %p\n", aParent));
96
97 ComAssertRet(aParent, E_INVALIDARG);
98
99 /* Enclose the state transition NotReady->InInit->Ready */
100 AutoInitSpan autoInitSpan(this);
101 AssertReturn(autoInitSpan.isOk(), E_FAIL);
102
103 m = new Data();
104
105 /* share the parent weakly */
106 unconst(m->pParent) = aParent;
107 unconst(m->pMachine) = pMachine;
108 m->hVfsUefiVarStore = NIL_RTVFS;
109
110 autoInitSpan.setSucceeded();
111
112 LogFlowThisFuncLeave();
113 return S_OK;
114}
115
116
117/**
118 * Uninitializes the instance and sets the ready flag to FALSE.
119 * Called either from FinalRelease() or by the parent when it gets destroyed.
120 */
121void UefiVariableStore::uninit()
122{
123 LogFlowThisFuncEnter();
124
125 /* Enclose the state transition Ready->InUninit->NotReady */
126 AutoUninitSpan autoUninitSpan(this);
127 if (autoUninitSpan.uninitDone())
128 return;
129
130 Assert(m->hVfsUefiVarStore == NIL_RTVFS);
131
132 unconst(m->pParent) = NULL;
133 unconst(m->pMachine) = NULL;
134
135 delete m;
136 m = NULL;
137
138 LogFlowThisFuncLeave();
139}
140
141
142HRESULT UefiVariableStore::getSecureBootEnabled(BOOL *pfEnabled)
143{
144 /* the machine needs to be mutable */
145 AutoMutableStateDependency adep(m->pMachine);
146 if (FAILED(adep.rc())) return adep.rc();
147
148 HRESULT hrc = i_retainUefiVariableStore(true /*fReadonly*/);
149 if (FAILED(hrc)) return hrc;
150
151 AutoReadLock rlock(this COMMA_LOCKVAL_SRC_POS);
152
153 uint64_t cbVar = 0;
154 int vrc = i_uefiVarStoreQueryVarSz("PK", &cbVar);
155 if (RT_SUCCESS(vrc))
156 {
157 *pfEnabled = TRUE;
158
159 /* Check the SecureBootEnable variable for the override. */
160 vrc = i_uefiVarStoreQueryVarSz("SecureBootEnable", &cbVar);
161 if (RT_SUCCESS(vrc))
162 {
163 if (cbVar == sizeof(uint8_t))
164 {
165 uint8_t bVar = 0;
166 hrc = i_uefiVarStoreQueryVar("SecureBootEnable", &bVar, sizeof(bVar));
167 if (SUCCEEDED(hrc))
168 *pfEnabled = bVar == 0x0 ? FALSE : TRUE;
169 }
170 else
171 hrc = setError(E_FAIL, tr("The 'SecureBootEnable' variable size is bogus (expected 1, got %llu)"), cbVar);
172 }
173 else if (vrc != VERR_FILE_NOT_FOUND)
174 hrc = setError(E_FAIL, tr("Failed to query the 'SecureBootEnable' variable size: %Rrc"), vrc);
175 }
176 else if (vrc == VERR_FILE_NOT_FOUND) /* No platform key means no secure boot. */
177 *pfEnabled = FALSE;
178 else
179 hrc = setError(E_FAIL, tr("Failed to query the platform key variable size: %Rrc"), vrc);
180
181 i_releaseUefiVariableStore();
182 return hrc;
183}
184
185
186HRESULT UefiVariableStore::setSecureBootEnabled(BOOL fEnabled)
187{
188 /* the machine needs to be mutable */
189 AutoMutableStateDependency adep(m->pMachine);
190 if (FAILED(adep.rc())) return adep.rc();
191
192 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
193 if (FAILED(hrc)) return hrc;
194
195 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
196
197 EFI_GUID GuidSecureBootEnable = EFI_SECURE_BOOT_ENABLE_DISABLE_GUID;
198 uint64_t cbVar = 0;
199 int vrc = i_uefiVarStoreQueryVarSz("PK", &cbVar);
200 if (RT_SUCCESS(vrc))
201 {
202 uint8_t bVar = fEnabled ? 0x1 : 0x0;
203 hrc = i_uefiVarStoreSetVar(&GuidSecureBootEnable, "SecureBootEnable",
204 EFI_VAR_HEADER_ATTR_NON_VOLATILE
205 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
206 | EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS,
207 &bVar, sizeof(bVar));
208 }
209 else if (vrc == VERR_FILE_NOT_FOUND) /* No platform key means no secure boot support. */
210 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("Secure boot is not available because the platform key (PK) is not enrolled"));
211 else
212 hrc = setError(E_FAIL, tr("Failed to query the platform key variable size: %Rrc"), vrc);
213
214 i_releaseUefiVariableStore();
215 return hrc;
216}
217
218
219HRESULT UefiVariableStore::addVariable(const com::Utf8Str &aName, const com::Guid &aOwnerUuid,
220 const std::vector<UefiVariableAttributes_T> &aAttributes,
221 const std::vector<BYTE> &aData)
222{
223 /* the machine needs to be mutable */
224 AutoMutableStateDependency adep(m->pMachine);
225 if (FAILED(adep.rc())) return adep.rc();
226
227 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
228 if (FAILED(hrc)) return hrc;
229
230 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
231
232 uint32_t fAttr = i_uefiVarAttrToMask(aAttributes);
233 EFI_GUID OwnerGuid;
234 RTEfiGuidFromUuid(&OwnerGuid, aOwnerUuid.raw());
235 hrc = i_uefiVarStoreSetVar(&OwnerGuid, aName.c_str(), fAttr, &aData.front(), aData.size());
236
237 i_releaseUefiVariableStore();
238 return hrc;
239}
240
241
242HRESULT UefiVariableStore::deleteVariable(const com::Utf8Str &aName, const com::Guid &aOwnerUuid)
243{
244 RT_NOREF(aName, aOwnerUuid);
245 return E_NOTIMPL;
246}
247
248
249HRESULT UefiVariableStore::changeVariable(const com::Utf8Str &aName, const std::vector<BYTE> &aData)
250{
251 RT_NOREF(aName, aData);
252 return E_NOTIMPL;
253}
254
255
256HRESULT UefiVariableStore::queryVariableByName(const com::Utf8Str &aName, com::Guid &aOwnerUuid,
257 std::vector<UefiVariableAttributes_T> &aAttributes,
258 std::vector<BYTE> &aData)
259{
260 /* the machine needs to be mutable */
261 AutoMutableStateDependency adep(m->pMachine);
262 if (FAILED(adep.rc())) return adep.rc();
263
264 HRESULT hrc = i_retainUefiVariableStore(true /*fReadonly*/);
265 if (FAILED(hrc)) return hrc;
266
267 AutoReadLock rlock(this COMMA_LOCKVAL_SRC_POS);
268
269 uint32_t fAttr;
270 int vrc = i_uefiVarStoreQueryVarAttr(aName.c_str(), &fAttr);
271 if (RT_SUCCESS(vrc))
272 {
273 RTUUID OwnerUuid;
274 vrc = i_uefiVarStoreQueryVarOwnerUuid(aName.c_str(), &OwnerUuid);
275 if (RT_SUCCESS(vrc))
276 {
277 uint64_t cbVar = 0;
278 vrc = i_uefiVarStoreQueryVarSz(aName.c_str(), &cbVar);
279 if (RT_SUCCESS(vrc))
280 {
281 aData.resize(cbVar);
282 hrc = i_uefiVarStoreQueryVar(aName.c_str(), &aData.front(), aData.size());
283 if (SUCCEEDED(hrc))
284 {
285 aOwnerUuid = com::Guid(OwnerUuid);
286 i_uefiAttrMaskToVec(fAttr, aAttributes);
287 }
288 }
289 else
290 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the size of variable '%s': %Rrc"), aName.c_str(), vrc);
291 }
292 else
293 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the owner UUID of variable '%s': %Rrc"), aName.c_str(), vrc);
294 }
295 else
296 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the attributes of variable '%s': %Rrc"), aName.c_str(), vrc);
297
298 i_releaseUefiVariableStore();
299 return hrc;
300}
301
302
303HRESULT UefiVariableStore::queryVariables(std::vector<com::Utf8Str> &aNames,
304 std::vector<com::Guid> &aOwnerUuids)
305{
306 /* the machine needs to be mutable */
307 AutoMutableStateDependency adep(m->pMachine);
308 if (FAILED(adep.rc())) return adep.rc();
309
310 HRESULT hrc = i_retainUefiVariableStore(true /*fReadonly*/);
311 if (FAILED(hrc)) return hrc;
312
313 AutoReadLock rlock(this COMMA_LOCKVAL_SRC_POS);
314
315 RTVFSDIR hVfsDir = NIL_RTVFSDIR;
316 int vrc = RTVfsDirOpen(m->hVfsUefiVarStore, "by-name", 0 /*fFlags*/, &hVfsDir);
317 if (RT_SUCCESS(vrc))
318 {
319 RTDIRENTRYEX DirEntry;
320
321 vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
322 for (;;)
323 {
324 RTUUID OwnerUuid;
325 vrc = i_uefiVarStoreQueryVarOwnerUuid(DirEntry.szName, &OwnerUuid);
326 if (RT_FAILURE(vrc))
327 break;
328
329 aNames.push_back(Utf8Str(DirEntry.szName));
330 aOwnerUuids.push_back(com::Guid(OwnerUuid));
331
332 vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
333 if (RT_FAILURE(vrc))
334 break;
335 }
336
337 if (vrc == VERR_NO_MORE_FILES)
338 vrc = VINF_SUCCESS;
339
340 RTVfsDirRelease(hVfsDir);
341 }
342
343 i_releaseUefiVariableStore();
344
345 if (RT_FAILURE(vrc))
346 return setError(VBOX_E_IPRT_ERROR, tr("Failed to query the variables: %Rrc"), vrc);
347
348 return S_OK;
349}
350
351
352HRESULT UefiVariableStore::enrollOraclePlatformKey(void)
353{
354 /* the machine needs to be mutable */
355 AutoMutableStateDependency adep(m->pMachine);
356 if (FAILED(adep.rc())) return adep.rc();
357
358 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
359 if (FAILED(hrc)) return hrc;
360
361 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
362
363 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
364
365 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
366 EFI_GUID GuidOwnerVBox = EFI_SIGNATURE_OWNER_GUID_VBOX;
367 RTUUID UuidVBox;
368 RTEfiGuidToUuid(&UuidVBox, &GuidOwnerVBox);
369
370 const com::Guid GuidVBox(UuidVBox);
371
372 hrc = i_uefiVarStoreAddSignatureToDb(&GuidGlobalVar, "PK", g_abUefiOracleDefPk, g_cbUefiOracleDefPk,
373 GuidVBox, SignatureType_X509);
374
375 i_releaseUefiVariableStore();
376 return hrc;
377}
378
379
380HRESULT UefiVariableStore::enrollPlatformKey(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid)
381{
382 /* the machine needs to be mutable */
383 AutoMutableStateDependency adep(m->pMachine);
384 if (FAILED(adep.rc())) return adep.rc();
385
386 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
387 if (FAILED(hrc)) return hrc;
388
389 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
390
391 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
392 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "PK", aData, aOwnerUuid, SignatureType_X509);
393
394 i_releaseUefiVariableStore();
395 return hrc;
396}
397
398
399HRESULT UefiVariableStore::addKek(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
400{
401 /* the machine needs to be mutable */
402 AutoMutableStateDependency adep(m->pMachine);
403 if (FAILED(adep.rc())) return adep.rc();
404
405 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
406 if (FAILED(hrc)) return hrc;
407
408 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
409
410 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
411 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "KEK", aData, aOwnerUuid, enmSignatureType);
412
413 i_releaseUefiVariableStore();
414 return hrc;
415}
416
417
418HRESULT UefiVariableStore::addSignatureToDb(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
419{
420 /* the machine needs to be mutable */
421 AutoMutableStateDependency adep(m->pMachine);
422 if (FAILED(adep.rc())) return adep.rc();
423
424 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
425 if (FAILED(hrc)) return hrc;
426
427 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
428
429 EFI_GUID GuidSecurityDb = EFI_GLOBAL_VARIABLE_GUID;
430 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "db", aData, aOwnerUuid, enmSignatureType);
431
432 i_releaseUefiVariableStore();
433 return hrc;
434}
435
436
437HRESULT UefiVariableStore::addSignatureToDbx(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
438{
439 /* the machine needs to be mutable */
440 AutoMutableStateDependency adep(m->pMachine);
441 if (FAILED(adep.rc())) return adep.rc();
442
443 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
444 if (FAILED(hrc)) return hrc;
445
446 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
447
448 EFI_GUID GuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
449 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "dbx", aData, aOwnerUuid, enmSignatureType);
450
451 i_releaseUefiVariableStore();
452 return hrc;
453}
454
455
456HRESULT UefiVariableStore::enrollDefaultMsSignatures(void)
457{
458 AutoMutableStateDependency adep(m->pMachine);
459 if (FAILED(adep.rc())) return adep.rc();
460
461 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
462 if (FAILED(hrc)) return hrc;
463
464 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
465
466 EFI_GUID EfiGuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
467 EFI_GUID EfiGuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
468
469 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
470 EFI_GUID EfiGuidMs = EFI_SIGNATURE_OWNER_GUID_MICROSOFT;
471 RTUUID UuidMs;
472 RTEfiGuidToUuid(&UuidMs, &EfiGuidMs);
473
474 const com::Guid GuidMs(UuidMs);
475
476 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidGlobalVar, "KEK", g_abUefiMicrosoftKek, g_cbUefiMicrosoftKek,
477 GuidMs, SignatureType_X509);
478 if (SUCCEEDED(hrc))
479 {
480 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftCa, g_cbUefiMicrosoftCa,
481 GuidMs, SignatureType_X509);
482 if (SUCCEEDED(hrc))
483 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftProPca, g_cbUefiMicrosoftProPca,
484 GuidMs, SignatureType_X509);
485 }
486
487 i_releaseUefiVariableStore();
488 return hrc;
489}
490
491
492/**
493 * Sets the given attributes for the given EFI variable store variable.
494 *
495 * @returns IPRT status code.
496 * @param pszVar The variable to set the attributes for.
497 * @param fAttr The attributes to set, see EFI_VAR_HEADER_ATTR_XXX.
498 */
499int UefiVariableStore::i_uefiVarStoreSetVarAttr(const char *pszVar, uint32_t fAttr)
500{
501 char szVarPath[_1K];
502 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
503 Assert(cch > 0); RT_NOREF(cch);
504
505 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
506 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
507 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
508 &hVfsFileAttr);
509 if (RT_SUCCESS(vrc))
510 {
511 uint32_t fAttrLe = RT_H2LE_U32(fAttr);
512 vrc = RTVfsFileWrite(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbWritten*/);
513 RTVfsFileRelease(hVfsFileAttr);
514 }
515
516 return vrc;
517}
518
519
520/**
521 * Queries the attributes for the given EFI variable store variable.
522 *
523 * @returns IPRT status code.
524 * @param pszVar The variable to query the attributes for.
525 * @param pfAttr Where to store the attributes on success.
526 */
527int UefiVariableStore::i_uefiVarStoreQueryVarAttr(const char *pszVar, uint32_t *pfAttr)
528{
529 char szVarPath[_1K];
530 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
531 Assert(cch > 0); RT_NOREF(cch);
532
533 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
534 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
535 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
536 &hVfsFileAttr);
537 if (RT_SUCCESS(vrc))
538 {
539 uint32_t fAttrLe = 0;
540 vrc = RTVfsFileRead(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbRead*/);
541 RTVfsFileRelease(hVfsFileAttr);
542 if (RT_SUCCESS(vrc))
543 *pfAttr = RT_LE2H_U32(fAttrLe);
544 }
545
546 return vrc;
547}
548
549
550/**
551 * Queries the data size for the given variable.
552 *
553 * @returns IPRT status code.
554 * @param pszVar The variable to query the size for.
555 * @param pcbVar Where to store the size of the variable data on success.
556 */
557int UefiVariableStore::i_uefiVarStoreQueryVarSz(const char *pszVar, uint64_t *pcbVar)
558{
559 char szVarPath[_1K];
560 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
561 Assert(cch > 0); RT_NOREF(cch);
562
563 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
564 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
565 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
566 &hVfsFile);
567 if (RT_SUCCESS(vrc))
568 {
569 vrc = RTVfsFileQuerySize(hVfsFile, pcbVar);
570 RTVfsFileRelease(hVfsFile);
571 }
572 else if (vrc == VERR_PATH_NOT_FOUND)
573 vrc = VERR_FILE_NOT_FOUND;
574
575 return vrc;
576}
577
578
579/**
580 * Returns the owner UUID of the given variable.
581 *
582 * @returns IPRT status code.
583 * @param pszVar The variable to query the owner UUID for.
584 * @param pUuid Where to store the owner UUID on success.
585 */
586int UefiVariableStore::i_uefiVarStoreQueryVarOwnerUuid(const char *pszVar, PRTUUID pUuid)
587{
588 char szVarPath[_1K];
589 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/uuid", pszVar);
590 Assert(cch > 0); RT_NOREF(cch);
591
592 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
593 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
594 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
595 &hVfsFileAttr);
596 if (RT_SUCCESS(vrc))
597 {
598 EFI_GUID OwnerGuid;
599 vrc = RTVfsFileRead(hVfsFileAttr, &OwnerGuid, sizeof(OwnerGuid), NULL /*pcbRead*/);
600 RTVfsFileRelease(hVfsFileAttr);
601 if (RT_SUCCESS(vrc))
602 RTEfiGuidToUuid(pUuid, &OwnerGuid);
603 }
604
605 return vrc;
606}
607
608
609/**
610 * Converts the given vector of variables attributes to a bitmask used internally.
611 *
612 * @returns Mask of UEFI variable attributes.
613 * @param vecAttributes Vector of variable atttributes.
614 */
615uint32_t UefiVariableStore::i_uefiVarAttrToMask(const std::vector<UefiVariableAttributes_T> &vecAttributes)
616{
617 uint32_t fAttr = 0;
618
619 for (size_t i = 0; i < vecAttributes.size(); i++)
620 fAttr |= (ULONG)vecAttributes[i];
621
622 return fAttr;
623}
624
625
626/**
627 * Converts the given aatribute mask to the attribute vector used externally.
628 *
629 * @returns nothing.
630 * @param fAttr The attribute mask.
631 * @param aAttributes The vector to store the attibutes in.
632 */
633void UefiVariableStore::i_uefiAttrMaskToVec(uint32_t fAttr, std::vector<UefiVariableAttributes_T> &aAttributes)
634{
635 if (fAttr & EFI_VAR_HEADER_ATTR_NON_VOLATILE)
636 aAttributes.push_back(UefiVariableAttributes_NonVolatile);
637 if (fAttr & EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS)
638 aAttributes.push_back(UefiVariableAttributes_BootServiceAccess);
639 if (fAttr & EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS)
640 aAttributes.push_back(UefiVariableAttributes_RuntimeAccess);
641 if (fAttr & EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD)
642 aAttributes.push_back(UefiVariableAttributes_HwErrorRecord);
643 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS)
644 aAttributes.push_back(UefiVariableAttributes_AuthWriteAccess);
645 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS)
646 aAttributes.push_back(UefiVariableAttributes_AuthTimeBasedWriteAccess);
647 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE)
648 aAttributes.push_back(UefiVariableAttributes_AuthAppendWrite);
649}
650
651
652/**
653 * Retains the reference of the variable store from the parent.
654 *
655 * @returns COM status code.
656 * @param fReadonly Flag whether the access is readonly.
657 */
658HRESULT UefiVariableStore::i_retainUefiVariableStore(bool fReadonly)
659{
660 Assert(m->hVfsUefiVarStore = NIL_RTVFS);
661 return m->pParent->i_retainUefiVarStore(&m->hVfsUefiVarStore, fReadonly);
662}
663
664
665/**
666 * Releases the reference of the variable store from the parent.
667 *
668 * @returns COM status code.
669 */
670HRESULT UefiVariableStore::i_releaseUefiVariableStore(void)
671{
672 RTVFS hVfs = m->hVfsUefiVarStore;
673
674 m->hVfsUefiVarStore = NIL_RTVFS;
675 return m->pParent->i_releaseUefiVarStore(hVfs);
676}
677
678
679/**
680 * Adds the given variable to the variable store.
681 *
682 * @returns IPRT status code.
683 * @param pGuid The EFI GUID of the variable.
684 * @param pszVar The variable name.
685 * @param fAttr Attributes for the variable.
686 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
687 */
688HRESULT UefiVariableStore::i_uefiVarStoreAddVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, PRTVFSFILE phVfsFile)
689{
690 RTUUID UuidVar;
691 RTEfiGuidToUuid(&UuidVar, pGuid);
692
693 char szVarPath[_1K];
694 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-uuid/%RTuuid/%s", &UuidVar, pszVar);
695 Assert(cch > 0); RT_NOREF(cch);
696
697 HRESULT hrc = S_OK;
698 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
699 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
700 phVfsFile);
701 if ( vrc == VERR_PATH_NOT_FOUND
702 || vrc == VERR_FILE_NOT_FOUND)
703 {
704 /*
705 * Try to create the owner GUID of the variable by creating the appropriate directory,
706 * ignore error if it exists already.
707 */
708 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
709 vrc = RTVfsOpenRoot(m->hVfsUefiVarStore, &hVfsDirRoot);
710 if (RT_SUCCESS(vrc))
711 {
712 char szGuidPath[_1K];
713 cch = RTStrPrintf2(szGuidPath, sizeof(szGuidPath), "by-uuid/%RTuuid", &UuidVar);
714 Assert(cch > 0);
715
716 RTVFSDIR hVfsDirGuid = NIL_RTVFSDIR;
717 vrc = RTVfsDirCreateDir(hVfsDirRoot, szGuidPath, 0755, 0 /*fFlags*/, &hVfsDirGuid);
718 if (RT_SUCCESS(vrc))
719 RTVfsDirRelease(hVfsDirGuid);
720 else if (vrc == VERR_ALREADY_EXISTS)
721 vrc = VINF_SUCCESS;
722
723 RTVfsDirRelease(hVfsDirRoot);
724 }
725 else
726 hrc = setError(E_FAIL, tr("Opening variable storage root directory failed: %Rrc"), vrc);
727
728 if (RT_SUCCESS(vrc))
729 {
730 vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
731 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE,
732 phVfsFile);
733 if (RT_SUCCESS(vrc))
734 vrc = i_uefiVarStoreSetVarAttr(pszVar, fAttr);
735 }
736
737 if (RT_FAILURE(vrc))
738 hrc = setError(E_FAIL, tr("Creating the variable '%s' failed: %Rrc"), pszVar, vrc);
739 }
740
741 return hrc;
742}
743
744
745HRESULT UefiVariableStore::i_uefiVarStoreSetVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, const void *pvData, size_t cbData)
746{
747 RTVFSFILE hVfsFileVar = NIL_RTVFSFILE;
748
749 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszVar, fAttr, &hVfsFileVar);
750 if (SUCCEEDED(hrc))
751 {
752 int vrc = RTVfsFileWrite(hVfsFileVar, pvData, cbData, NULL /*pcbWritten*/);
753 if (RT_FAILURE(vrc))
754 hrc = setError(E_FAIL, tr("Setting the variable '%s' failed: %Rrc"), pszVar, vrc);
755
756 RTVfsFileRelease(hVfsFileVar);
757 }
758
759 return hrc;
760}
761
762
763HRESULT UefiVariableStore::i_uefiVarStoreQueryVar(const char *pszVar, void *pvData, size_t cbData)
764{
765 HRESULT hrc = S_OK;
766
767 char szVarPath[_1K];
768 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
769 Assert(cch > 0); RT_NOREF(cch);
770
771 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
772 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
773 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
774 &hVfsFile);
775 if (RT_SUCCESS(vrc))
776 {
777 vrc = RTVfsFileRead(hVfsFile, pvData, cbData, NULL /*pcbRead*/);
778 if (RT_FAILURE(vrc))
779 hrc = setError(E_FAIL, tr("Failed to read data of variable '%s': %Rrc"), pszVar, vrc);
780
781 RTVfsFileRelease(hVfsFile);
782 }
783 else
784 hrc = setError(E_FAIL, tr("Failed to open variable '%s' for reading: %Rrc"), pszVar, vrc);
785
786 return hrc;
787}
788
789HRESULT UefiVariableStore::i_uefiSigDbAddSig(RTEFISIGDB hEfiSigDb, const void *pvData, size_t cbData,
790 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
791{
792 RTEFISIGTYPE enmSigType = RTEFISIGTYPE_INVALID;
793
794 switch (enmSignatureType)
795 {
796 case SignatureType_X509:
797 enmSigType = RTEFISIGTYPE_X509;
798 break;
799 case SignatureType_Sha256:
800 enmSigType = RTEFISIGTYPE_SHA256;
801 break;
802 default:
803 return setError(E_FAIL, tr("The given signature type is not supported"));
804 }
805
806 int vrc = RTEfiSigDbAddSignatureFromBuf(hEfiSigDb, enmSigType, aOwnerUuid.raw(), pvData, cbData);
807 if (RT_SUCCESS(vrc))
808 return S_OK;
809
810 return setError(E_FAIL, tr("Failed to add signature to the database (%Rrc)"), vrc);
811}
812
813
814HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDb(PCEFI_GUID pGuid, const char *pszDb, const void *pvData, size_t cbData,
815 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
816{
817 RTVFSFILE hVfsFileSigDb = NIL_RTVFSFILE;
818
819 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszDb,
820 EFI_VAR_HEADER_ATTR_NON_VOLATILE
821 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
822 | EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS
823 | EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS,
824 &hVfsFileSigDb);
825 if (SUCCEEDED(hrc))
826 {
827 RTEFISIGDB hEfiSigDb;
828
829 int vrc = RTEfiSigDbCreate(&hEfiSigDb);
830 if (RT_SUCCESS(vrc))
831 {
832 vrc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFileSigDb);
833 if (RT_SUCCESS(vrc))
834 {
835 hrc = i_uefiSigDbAddSig(hEfiSigDb, pvData, cbData, aOwnerUuid, enmSignatureType);
836 if (SUCCEEDED(hrc))
837 {
838 vrc = RTVfsFileSeek(hVfsFileSigDb, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
839 AssertRC(vrc);
840
841 vrc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFileSigDb);
842 if (RT_FAILURE(vrc))
843 hrc = setError(E_FAIL, tr("Writing updated signature database failed: %Rrc"), vrc);
844 }
845 }
846 else
847 hrc = setError(E_FAIL, tr("Loading signature database failed: %Rrc"), vrc);
848
849 RTEfiSigDbDestroy(hEfiSigDb);
850 }
851 else
852 hrc = setError(E_FAIL, tr("Creating signature database failed: %Rrc"), vrc);
853
854 RTVfsFileRelease(hVfsFileSigDb);
855 }
856
857 return hrc;
858}
859
860
861HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDbVec(PCEFI_GUID pGuid, const char *pszDb, const std::vector<BYTE> &aData,
862 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
863{
864 return i_uefiVarStoreAddSignatureToDb(pGuid, pszDb, &aData.front(), aData.size(), aOwnerUuid, enmSignatureType);
865}
866
867/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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