VirtualBox

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

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

Main: Implement enrolling the default VBox platform key, bugref:9580

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 KB
Line 
1/* $Id: UefiVariableStoreImpl.cpp 91490 2021-09-30 08:30:25Z 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 * @param hVfsUefiVarStore The UEFI variable store VFS handle.
92 */
93HRESULT UefiVariableStore::init(NvramStore *aParent, Machine *pMachine, RTVFS hVfsUefiVarStore)
94{
95 LogFlowThisFuncEnter();
96 LogFlowThisFunc(("aParent: %p\n", aParent));
97
98 ComAssertRet(aParent, E_INVALIDARG);
99
100 /* Enclose the state transition NotReady->InInit->Ready */
101 AutoInitSpan autoInitSpan(this);
102 AssertReturn(autoInitSpan.isOk(), E_FAIL);
103
104 m = new Data();
105
106 /* share the parent weakly */
107 unconst(m->pParent) = aParent;
108 unconst(m->pMachine) = pMachine;
109 m->hVfsUefiVarStore = hVfsUefiVarStore;
110
111 autoInitSpan.setSucceeded();
112
113 LogFlowThisFuncLeave();
114 return S_OK;
115}
116
117
118/**
119 * Uninitializes the instance and sets the ready flag to FALSE.
120 * Called either from FinalRelease() or by the parent when it gets destroyed.
121 */
122void UefiVariableStore::uninit()
123{
124 LogFlowThisFuncEnter();
125
126 /* Enclose the state transition Ready->InUninit->NotReady */
127 AutoUninitSpan autoUninitSpan(this);
128 if (autoUninitSpan.uninitDone())
129 return;
130
131 RTVfsRelease(m->hVfsUefiVarStore);
132
133 unconst(m->pParent) = NULL;
134 unconst(m->pMachine) = NULL;
135
136 delete m;
137 m = NULL;
138
139 LogFlowThisFuncLeave();
140}
141
142
143HRESULT UefiVariableStore::getSecureBootEnabled(BOOL *pfEnabled)
144{
145 /* the machine needs to be mutable */
146 AutoMutableStateDependency adep(m->pMachine);
147 if (FAILED(adep.rc())) return adep.rc();
148
149 AutoReadLock rlock(this COMMA_LOCKVAL_SRC_POS);
150
151 HRESULT hrc = S_OK;
152 uint64_t cbVar = 0;
153 int vrc = i_uefiVarStoreQueryVarSz("PK", &cbVar);
154 if (RT_SUCCESS(vrc))
155 {
156 *pfEnabled = TRUE;
157
158 /* Check the SecureBootEnable variable for the override. */
159 vrc = i_uefiVarStoreQueryVarSz("SecureBootEnable", &cbVar);
160 if (RT_SUCCESS(vrc))
161 {
162 if (cbVar == sizeof(uint8_t))
163 {
164 uint8_t bVar = 0;
165 hrc = i_uefiVarStoreQueryVar("SecureBootEnable", &bVar, sizeof(bVar));
166 if (SUCCEEDED(hrc))
167 *pfEnabled = bVar == 0x0 ? FALSE : TRUE;
168 }
169 else
170 hrc = setError(E_FAIL, tr("The 'SecureBootEnable' variable size is bogus (expected 1, got %llu)"), cbVar);
171 }
172 else if (vrc != VERR_FILE_NOT_FOUND)
173 hrc = setError(E_FAIL, tr("Failed to query the 'SecureBootEnable' variable size: %Rrc"), vrc);
174 }
175 else if (vrc == VERR_FILE_NOT_FOUND) /* No platform key means no secure boot. */
176 *pfEnabled = FALSE;
177 else
178 hrc = setError(E_FAIL, tr("Failed to query the platform key variable size: %Rrc"), vrc);
179
180 return hrc;
181}
182
183
184HRESULT UefiVariableStore::setSecureBootEnabled(BOOL fEnabled)
185{
186 /* the machine needs to be mutable */
187 AutoMutableStateDependency adep(m->pMachine);
188 if (FAILED(adep.rc())) return adep.rc();
189
190 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
191
192 EFI_GUID GuidSecureBootEnable = EFI_SECURE_BOOT_ENABLE_DISABLE_GUID;
193 uint64_t cbVar = 0;
194 int vrc = i_uefiVarStoreQueryVarSz("PK", &cbVar);
195 if (RT_SUCCESS(vrc))
196 {
197 uint8_t bVar = fEnabled ? 0x1 : 0x0;
198 return i_uefiVarStoreSetVar(&GuidSecureBootEnable, "SecureBootEnable",
199 EFI_VAR_HEADER_ATTR_NON_VOLATILE
200 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
201 | EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS,
202 &bVar, sizeof(bVar));
203 }
204 else if (vrc == VERR_FILE_NOT_FOUND) /* No platform key means no secure boot support. */
205 return setError(VBOX_E_OBJECT_NOT_FOUND, tr("Secure boot is not available because the platform key (PK) is not enrolled"));
206
207 return setError(E_FAIL, tr("Failed to query the platform key variable size: %Rrc"), vrc);
208}
209
210
211HRESULT UefiVariableStore::addVariable(const com::Utf8Str &aName, const com::Guid &aOwnerUuid,
212 const std::vector<UefiVariableAttributes_T> &aAttributes,
213 const std::vector<BYTE> &aData)
214{
215 /* the machine needs to be mutable */
216 AutoMutableStateDependency adep(m->pMachine);
217 if (FAILED(adep.rc())) return adep.rc();
218
219 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
220
221 uint32_t fAttr = i_uefiVarAttrToMask(aAttributes);
222 EFI_GUID OwnerGuid;
223 RTEfiGuidFromUuid(&OwnerGuid, aOwnerUuid.raw());
224 return i_uefiVarStoreSetVar(&OwnerGuid, aName.c_str(), fAttr, &aData.front(), aData.size());
225}
226
227
228HRESULT UefiVariableStore::deleteVariable(const com::Utf8Str &aName, const com::Guid &aOwnerUuid)
229{
230 RT_NOREF(aName, aOwnerUuid);
231 return E_NOTIMPL;
232}
233
234
235HRESULT UefiVariableStore::changeVariable(const com::Utf8Str &aName, const std::vector<BYTE> &aData)
236{
237 RT_NOREF(aName, aData);
238 return E_NOTIMPL;
239}
240
241
242HRESULT UefiVariableStore::queryVariableByName(const com::Utf8Str &aName, com::Guid &aOwnerUuid,
243 std::vector<UefiVariableAttributes_T> &aAttributes,
244 std::vector<BYTE> &aData)
245{
246 RT_NOREF(aName, aOwnerUuid, aAttributes, aData);
247
248 HRESULT hrc = S_OK;
249 uint32_t fAttr;
250 int vrc = i_uefiVarStoreQueryVarAttr(aName.c_str(), &fAttr);
251 if (RT_SUCCESS(vrc))
252 {
253 RTUUID OwnerUuid;
254 vrc = i_uefiVarStoreQueryVarOwnerUuid(aName.c_str(), &OwnerUuid);
255 if (RT_SUCCESS(vrc))
256 {
257 uint64_t cbVar = 0;
258 vrc = i_uefiVarStoreQueryVarSz(aName.c_str(), &cbVar);
259 if (RT_SUCCESS(vrc))
260 {
261 aData.resize(cbVar);
262 hrc = i_uefiVarStoreQueryVar(aName.c_str(), &aData.front(), aData.size());
263 if (SUCCEEDED(hrc))
264 {
265 aOwnerUuid = com::Guid(OwnerUuid);
266 i_uefiAttrMaskToVec(fAttr, aAttributes);
267 }
268 }
269 else
270 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the size of variable '%s': %Rrc"), aName.c_str(), vrc);
271 }
272 else
273 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the owner UUID of variable '%s': %Rrc"), aName.c_str(), vrc);
274 }
275 else
276 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the attributes of variable '%s': %Rrc"), aName.c_str(), vrc);
277
278 return hrc;
279}
280
281
282HRESULT UefiVariableStore::queryVariables(std::vector<com::Utf8Str> &aNames,
283 std::vector<com::Guid> &aOwnerUuids)
284{
285 /* the machine needs to be mutable */
286 AutoMutableStateDependency adep(m->pMachine);
287 if (FAILED(adep.rc())) return adep.rc();
288
289 AutoReadLock rlock(this COMMA_LOCKVAL_SRC_POS);
290
291 RTVFSDIR hVfsDir = NIL_RTVFSDIR;
292 int vrc = RTVfsDirOpen(m->hVfsUefiVarStore, "by-name", 0 /*fFlags*/, &hVfsDir);
293 if (RT_SUCCESS(vrc))
294 {
295 RTDIRENTRYEX DirEntry;
296
297 vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
298 for (;;)
299 {
300 RTUUID OwnerUuid;
301 vrc = i_uefiVarStoreQueryVarOwnerUuid(DirEntry.szName, &OwnerUuid);
302 if (RT_FAILURE(vrc))
303 break;
304
305 aNames.push_back(Utf8Str(DirEntry.szName));
306 aOwnerUuids.push_back(com::Guid(OwnerUuid));
307
308 vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
309 if (RT_FAILURE(vrc))
310 break;
311 }
312
313 if (vrc == VERR_NO_MORE_FILES)
314 vrc = VINF_SUCCESS;
315
316 RTVfsDirRelease(hVfsDir);
317 }
318
319 if (RT_FAILURE(vrc))
320 return setError(VBOX_E_IPRT_ERROR, tr("Failed to query the variables: %Rrc"), vrc);
321
322 return S_OK;
323}
324
325
326HRESULT UefiVariableStore::enrollOraclePlatformKey(void)
327{
328 /* the machine needs to be mutable */
329 AutoMutableStateDependency adep(m->pMachine);
330 if (FAILED(adep.rc())) return adep.rc();
331
332 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
333
334 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
335
336 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
337 EFI_GUID GuidOwnerVBox = EFI_SIGNATURE_OWNER_GUID_VBOX;
338 RTUUID UuidVBox;
339 RTEfiGuidToUuid(&UuidVBox, &GuidOwnerVBox);
340
341 const com::Guid GuidVBox(UuidVBox);
342
343 return i_uefiVarStoreAddSignatureToDb(&GuidGlobalVar, "PK", g_abUefiOracleDefPk, g_cbUefiOracleDefPk,
344 GuidVBox, SignatureType_X509);
345}
346
347
348HRESULT UefiVariableStore::enrollPlatformKey(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid)
349{
350 /* the machine needs to be mutable */
351 AutoMutableStateDependency adep(m->pMachine);
352 if (FAILED(adep.rc())) return adep.rc();
353
354 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
355
356 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
357 return i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "PK", aData, aOwnerUuid, SignatureType_X509);
358}
359
360
361HRESULT UefiVariableStore::addKek(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
362{
363 /* the machine needs to be mutable */
364 AutoMutableStateDependency adep(m->pMachine);
365 if (FAILED(adep.rc())) return adep.rc();
366
367 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
368
369 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
370 return i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "KEK", aData, aOwnerUuid, enmSignatureType);
371}
372
373
374HRESULT UefiVariableStore::addSignatureToDb(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
375{
376 /* the machine needs to be mutable */
377 AutoMutableStateDependency adep(m->pMachine);
378 if (FAILED(adep.rc())) return adep.rc();
379
380 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
381
382 EFI_GUID GuidSecurityDb = EFI_GLOBAL_VARIABLE_GUID;
383 return i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "db", aData, aOwnerUuid, enmSignatureType);
384}
385
386
387HRESULT UefiVariableStore::addSignatureToDbx(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
388{
389 /* the machine needs to be mutable */
390 AutoMutableStateDependency adep(m->pMachine);
391 if (FAILED(adep.rc())) return adep.rc();
392
393 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
394
395 EFI_GUID GuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
396 return i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "dbx", aData, aOwnerUuid, enmSignatureType);
397}
398
399
400HRESULT UefiVariableStore::enrollDefaultMsSignatures(void)
401{
402 AutoMutableStateDependency adep(m->pMachine);
403 if (FAILED(adep.rc())) return adep.rc();
404
405 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
406
407 EFI_GUID EfiGuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
408 EFI_GUID EfiGuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
409
410 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
411 EFI_GUID EfiGuidMs = EFI_SIGNATURE_OWNER_GUID_MICROSOFT;
412 RTUUID UuidMs;
413 RTEfiGuidToUuid(&UuidMs, &EfiGuidMs);
414
415 const com::Guid GuidMs(UuidMs);
416
417 HRESULT hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidGlobalVar, "KEK", g_abUefiMicrosoftKek, g_cbUefiMicrosoftKek,
418 GuidMs, SignatureType_X509);
419 if (SUCCEEDED(hrc))
420 {
421 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftCa, g_cbUefiMicrosoftCa,
422 GuidMs, SignatureType_X509);
423 if (SUCCEEDED(hrc))
424 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftProPca, g_cbUefiMicrosoftProPca,
425 GuidMs, SignatureType_X509);
426 }
427
428 return hrc;
429}
430
431
432/**
433 * Sets the given attributes for the given EFI variable store variable.
434 *
435 * @returns IPRT status code.
436 * @param pszVar The variable to set the attributes for.
437 * @param fAttr The attributes to set, see EFI_VAR_HEADER_ATTR_XXX.
438 */
439int UefiVariableStore::i_uefiVarStoreSetVarAttr(const char *pszVar, uint32_t fAttr)
440{
441 char szVarPath[_1K];
442 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
443 Assert(cch > 0); RT_NOREF(cch);
444
445 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
446 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
447 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
448 &hVfsFileAttr);
449 if (RT_SUCCESS(vrc))
450 {
451 uint32_t fAttrLe = RT_H2LE_U32(fAttr);
452 vrc = RTVfsFileWrite(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbWritten*/);
453 RTVfsFileRelease(hVfsFileAttr);
454 }
455
456 return vrc;
457}
458
459
460/**
461 * Queries the attributes for the given EFI variable store variable.
462 *
463 * @returns IPRT status code.
464 * @param pszVar The variable to query the attributes for.
465 * @param pfAttr Where to store the attributes on success.
466 */
467int UefiVariableStore::i_uefiVarStoreQueryVarAttr(const char *pszVar, uint32_t *pfAttr)
468{
469 char szVarPath[_1K];
470 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
471 Assert(cch > 0); RT_NOREF(cch);
472
473 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
474 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
475 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
476 &hVfsFileAttr);
477 if (RT_SUCCESS(vrc))
478 {
479 uint32_t fAttrLe = 0;
480 vrc = RTVfsFileRead(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbRead*/);
481 RTVfsFileRelease(hVfsFileAttr);
482 if (RT_SUCCESS(vrc))
483 *pfAttr = RT_LE2H_U32(fAttrLe);
484 }
485
486 return vrc;
487}
488
489
490/**
491 * Queries the data size for the given variable.
492 *
493 * @returns IPRT status code.
494 * @param pszVar The variable to query the size for.
495 * @param pcbVar Where to store the size of the variable data on success.
496 */
497int UefiVariableStore::i_uefiVarStoreQueryVarSz(const char *pszVar, uint64_t *pcbVar)
498{
499 char szVarPath[_1K];
500 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
501 Assert(cch > 0); RT_NOREF(cch);
502
503 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
504 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
505 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
506 &hVfsFile);
507 if (RT_SUCCESS(vrc))
508 {
509 vrc = RTVfsFileQuerySize(hVfsFile, pcbVar);
510 RTVfsFileRelease(hVfsFile);
511 }
512 else if (vrc == VERR_PATH_NOT_FOUND)
513 vrc = VERR_FILE_NOT_FOUND;
514
515 return vrc;
516}
517
518
519/**
520 * Returns the owner UUID of the given variable.
521 *
522 * @returns IPRT status code.
523 * @param pszVar The variable to query the owner UUID for.
524 * @param pUuid Where to store the owner UUID on success.
525 */
526int UefiVariableStore::i_uefiVarStoreQueryVarOwnerUuid(const char *pszVar, PRTUUID pUuid)
527{
528 char szVarPath[_1K];
529 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/uuid", pszVar);
530 Assert(cch > 0); RT_NOREF(cch);
531
532 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
533 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
534 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
535 &hVfsFileAttr);
536 if (RT_SUCCESS(vrc))
537 {
538 EFI_GUID OwnerGuid;
539 vrc = RTVfsFileRead(hVfsFileAttr, &OwnerGuid, sizeof(OwnerGuid), NULL /*pcbRead*/);
540 RTVfsFileRelease(hVfsFileAttr);
541 if (RT_SUCCESS(vrc))
542 RTEfiGuidToUuid(pUuid, &OwnerGuid);
543 }
544
545 return vrc;
546}
547
548
549/**
550 * Converts the given vector of variables attributes to a bitmask used internally.
551 *
552 * @returns Mask of UEFI variable attributes.
553 * @param vecAttributes Vector of variable atttributes.
554 */
555uint32_t UefiVariableStore::i_uefiVarAttrToMask(const std::vector<UefiVariableAttributes_T> &vecAttributes)
556{
557 uint32_t fAttr = 0;
558
559 for (size_t i = 0; i < vecAttributes.size(); i++)
560 fAttr |= (ULONG)vecAttributes[i];
561
562 return fAttr;
563}
564
565
566/**
567 * Converts the given aatribute mask to the attribute vector used externally.
568 *
569 * @returns nothing.
570 * @param fAttr The attribute mask.
571 * @param aAttributes The vector to store the attibutes in.
572 */
573void UefiVariableStore::i_uefiAttrMaskToVec(uint32_t fAttr, std::vector<UefiVariableAttributes_T> &aAttributes)
574{
575 if (fAttr & EFI_VAR_HEADER_ATTR_NON_VOLATILE)
576 aAttributes.push_back(UefiVariableAttributes_NonVolatile);
577 if (fAttr & EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS)
578 aAttributes.push_back(UefiVariableAttributes_BootServiceAccess);
579 if (fAttr & EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS)
580 aAttributes.push_back(UefiVariableAttributes_RuntimeAccess);
581 if (fAttr & EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD)
582 aAttributes.push_back(UefiVariableAttributes_HwErrorRecord);
583 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS)
584 aAttributes.push_back(UefiVariableAttributes_AuthWriteAccess);
585 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS)
586 aAttributes.push_back(UefiVariableAttributes_AuthTimeBasedWriteAccess);
587 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE)
588 aAttributes.push_back(UefiVariableAttributes_AuthAppendWrite);
589}
590
591
592/**
593 * Adds the given variable to the variable store.
594 *
595 * @returns IPRT status code.
596 * @param pGuid The EFI GUID of the variable.
597 * @param pszVar The variable name.
598 * @param fAttr Attributes for the variable.
599 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
600 */
601HRESULT UefiVariableStore::i_uefiVarStoreAddVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, PRTVFSFILE phVfsFile)
602{
603 RTUUID UuidVar;
604 RTEfiGuidToUuid(&UuidVar, pGuid);
605
606 char szVarPath[_1K];
607 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-uuid/%RTuuid/%s", &UuidVar, pszVar);
608 Assert(cch > 0); RT_NOREF(cch);
609
610 HRESULT hrc = S_OK;
611 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
612 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
613 phVfsFile);
614 if ( vrc == VERR_PATH_NOT_FOUND
615 || vrc == VERR_FILE_NOT_FOUND)
616 {
617 /*
618 * Try to create the owner GUID of the variable by creating the appropriate directory,
619 * ignore error if it exists already.
620 */
621 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
622 vrc = RTVfsOpenRoot(m->hVfsUefiVarStore, &hVfsDirRoot);
623 if (RT_SUCCESS(vrc))
624 {
625 char szGuidPath[_1K];
626 cch = RTStrPrintf2(szGuidPath, sizeof(szGuidPath), "by-uuid/%RTuuid", &UuidVar);
627 Assert(cch > 0);
628
629 RTVFSDIR hVfsDirGuid = NIL_RTVFSDIR;
630 vrc = RTVfsDirCreateDir(hVfsDirRoot, szGuidPath, 0755, 0 /*fFlags*/, &hVfsDirGuid);
631 if (RT_SUCCESS(vrc))
632 RTVfsDirRelease(hVfsDirGuid);
633 else if (vrc == VERR_ALREADY_EXISTS)
634 vrc = VINF_SUCCESS;
635
636 RTVfsDirRelease(hVfsDirRoot);
637 }
638 else
639 hrc = setError(E_FAIL, tr("Opening variable storage root directory failed: %Rrc"), vrc);
640
641 if (RT_SUCCESS(vrc))
642 {
643 vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
644 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE,
645 phVfsFile);
646 if (RT_SUCCESS(vrc))
647 vrc = i_uefiVarStoreSetVarAttr(pszVar, fAttr);
648 }
649
650 if (RT_FAILURE(vrc))
651 hrc = setError(E_FAIL, tr("Creating the variable '%s' failed: %Rrc"), pszVar, vrc);
652 }
653
654 return hrc;
655}
656
657
658HRESULT UefiVariableStore::i_uefiVarStoreSetVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, const void *pvData, size_t cbData)
659{
660 RTVFSFILE hVfsFileVar = NIL_RTVFSFILE;
661
662 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszVar, fAttr, &hVfsFileVar);
663 if (SUCCEEDED(hrc))
664 {
665 int vrc = RTVfsFileWrite(hVfsFileVar, pvData, cbData, NULL /*pcbWritten*/);
666 if (RT_FAILURE(vrc))
667 hrc = setError(E_FAIL, tr("Setting the variable '%s' failed: %Rrc"), pszVar, vrc);
668
669 RTVfsFileRelease(hVfsFileVar);
670 }
671
672 return hrc;
673}
674
675
676HRESULT UefiVariableStore::i_uefiVarStoreQueryVar(const char *pszVar, void *pvData, size_t cbData)
677{
678 HRESULT hrc = S_OK;
679
680 char szVarPath[_1K];
681 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
682 Assert(cch > 0); RT_NOREF(cch);
683
684 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
685 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
686 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
687 &hVfsFile);
688 if (RT_SUCCESS(vrc))
689 {
690 vrc = RTVfsFileRead(hVfsFile, pvData, cbData, NULL /*pcbRead*/);
691 if (RT_FAILURE(vrc))
692 hrc = setError(E_FAIL, tr("Failed to read data of variable '%s': %Rrc"), pszVar, vrc);
693
694 RTVfsFileRelease(hVfsFile);
695 }
696 else
697 hrc = setError(E_FAIL, tr("Failed to open variable '%s' for reading: %Rrc"), pszVar, vrc);
698
699 return hrc;
700}
701
702HRESULT UefiVariableStore::i_uefiSigDbAddSig(RTEFISIGDB hEfiSigDb, const void *pvData, size_t cbData,
703 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
704{
705 RTEFISIGTYPE enmSigType = RTEFISIGTYPE_INVALID;
706
707 switch (enmSignatureType)
708 {
709 case SignatureType_X509:
710 enmSigType = RTEFISIGTYPE_X509;
711 break;
712 case SignatureType_Sha256:
713 enmSigType = RTEFISIGTYPE_SHA256;
714 break;
715 default:
716 return setError(E_FAIL, tr("The given signature type is not supported"));
717 }
718
719 int vrc = RTEfiSigDbAddSignatureFromBuf(hEfiSigDb, enmSigType, aOwnerUuid.raw(), pvData, cbData);
720 if (RT_SUCCESS(vrc))
721 return S_OK;
722
723 return setError(E_FAIL, tr("Failed to add signature to the database (%Rrc)"), vrc);
724}
725
726
727HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDb(PCEFI_GUID pGuid, const char *pszDb, const void *pvData, size_t cbData,
728 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
729{
730 RTVFSFILE hVfsFileSigDb = NIL_RTVFSFILE;
731
732 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszDb,
733 EFI_VAR_HEADER_ATTR_NON_VOLATILE
734 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
735 | EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS
736 | EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS,
737 &hVfsFileSigDb);
738 if (SUCCEEDED(hrc))
739 {
740 RTEFISIGDB hEfiSigDb;
741
742 int vrc = RTEfiSigDbCreate(&hEfiSigDb);
743 if (RT_SUCCESS(vrc))
744 {
745 vrc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFileSigDb);
746 if (RT_SUCCESS(vrc))
747 {
748 hrc = i_uefiSigDbAddSig(hEfiSigDb, pvData, cbData, aOwnerUuid, enmSignatureType);
749 if (SUCCEEDED(hrc))
750 {
751 vrc = RTVfsFileSeek(hVfsFileSigDb, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
752 AssertRC(vrc);
753
754 vrc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFileSigDb);
755 if (RT_FAILURE(vrc))
756 hrc = setError(E_FAIL, tr("Writing updated signature database failed: %Rrc"), vrc);
757 }
758 }
759 else
760 hrc = setError(E_FAIL, tr("Loading signature database failed: %Rrc"), vrc);
761
762 RTEfiSigDbDestroy(hEfiSigDb);
763 }
764 else
765 hrc = setError(E_FAIL, tr("Creating signature database failed: %Rrc"), vrc);
766
767 RTVfsFileRelease(hVfsFileSigDb);
768 }
769
770 return hrc;
771}
772
773
774HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDbVec(PCEFI_GUID pGuid, const char *pszDb, const std::vector<BYTE> &aData,
775 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
776{
777 return i_uefiVarStoreAddSignatureToDb(pGuid, pszDb, &aData.front(), aData.size(), aOwnerUuid, enmSignatureType);
778}
779
780/* 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