VirtualBox

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

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

Main/UefiVariableStore,FE/VBoxManage: Implement API to delete and change the content of a UEFI variable and hook it up to VBoxManage, bugref:9580

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.5 KB
Line 
1/* $Id: UefiVariableStoreImpl.cpp 91685 2021-10-12 09:26:59Z 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(aOwnerUuid);
245
246 /* the machine needs to be mutable */
247 AutoMutableStateDependency adep(m->pMachine);
248 if (FAILED(adep.rc())) return adep.rc();
249
250 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
251 if (FAILED(hrc)) return hrc;
252
253 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
254
255 char szVarPath[_1K];
256 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s", aName.c_str());
257 if (cch > 0)
258 {
259 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
260 int vrc = RTVfsOpenRoot(m->hVfsUefiVarStore, &hVfsDirRoot);
261 if (RT_SUCCESS(vrc))
262 {
263 vrc = RTVfsDirRemoveDir(hVfsDirRoot, szVarPath, 0 /*fFlags*/);
264 RTVfsDirRelease(hVfsDirRoot);
265 if (RT_FAILURE(vrc))
266 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to remove variable '%s' (%Rrc)"), aName.c_str(), vrc);
267 }
268 else
269 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to open the variable store root (%Rrc)"), vrc);
270 }
271 else
272 hrc = setError(E_FAIL, tr("The variable name is too long"));
273
274 i_releaseUefiVariableStore();
275 return hrc;
276}
277
278
279HRESULT UefiVariableStore::changeVariable(const com::Utf8Str &aName, const std::vector<BYTE> &aData)
280{
281 /* the machine needs to be mutable */
282 AutoMutableStateDependency adep(m->pMachine);
283 if (FAILED(adep.rc())) return adep.rc();
284
285 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
286 if (FAILED(hrc)) return hrc;
287
288 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
289
290 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
291 hrc = i_uefiVarStoreOpenVar(aName.c_str(), &hVfsFile);
292 if (SUCCEEDED(hrc))
293 {
294 int vrc = RTVfsFileSetSize(hVfsFile, aData.size(), RTVFSFILE_SIZE_F_NORMAL);
295 if (RT_SUCCESS(vrc))
296 {
297 vrc = RTVfsFileWriteAt(hVfsFile, 0 /*off*/, &aData.front(), aData.size(), NULL /*pcbWritten*/);
298 if (RT_FAILURE(vrc))
299 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to data for variable '%s' (%Rrc)"), aName.c_str(), vrc);
300 }
301 else
302 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to allocate space for the variable '%s' (%Rrc)"), aName.c_str(), vrc);
303
304 RTVfsFileRelease(hVfsFile);
305 }
306
307 i_releaseUefiVariableStore();
308 return hrc;
309}
310
311
312HRESULT UefiVariableStore::queryVariableByName(const com::Utf8Str &aName, com::Guid &aOwnerUuid,
313 std::vector<UefiVariableAttributes_T> &aAttributes,
314 std::vector<BYTE> &aData)
315{
316 /* the machine needs to be mutable */
317 AutoMutableStateDependency adep(m->pMachine);
318 if (FAILED(adep.rc())) return adep.rc();
319
320 HRESULT hrc = i_retainUefiVariableStore(true /*fReadonly*/);
321 if (FAILED(hrc)) return hrc;
322
323 AutoReadLock rlock(this COMMA_LOCKVAL_SRC_POS);
324
325 uint32_t fAttr;
326 int vrc = i_uefiVarStoreQueryVarAttr(aName.c_str(), &fAttr);
327 if (RT_SUCCESS(vrc))
328 {
329 RTUUID OwnerUuid;
330 vrc = i_uefiVarStoreQueryVarOwnerUuid(aName.c_str(), &OwnerUuid);
331 if (RT_SUCCESS(vrc))
332 {
333 uint64_t cbVar = 0;
334 vrc = i_uefiVarStoreQueryVarSz(aName.c_str(), &cbVar);
335 if (RT_SUCCESS(vrc))
336 {
337 aData.resize(cbVar);
338 hrc = i_uefiVarStoreQueryVar(aName.c_str(), &aData.front(), aData.size());
339 if (SUCCEEDED(hrc))
340 {
341 aOwnerUuid = com::Guid(OwnerUuid);
342 i_uefiAttrMaskToVec(fAttr, aAttributes);
343 }
344 }
345 else
346 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the size of variable '%s': %Rrc"), aName.c_str(), vrc);
347 }
348 else
349 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the owner UUID of variable '%s': %Rrc"), aName.c_str(), vrc);
350 }
351 else
352 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to query the attributes of variable '%s': %Rrc"), aName.c_str(), vrc);
353
354 i_releaseUefiVariableStore();
355 return hrc;
356}
357
358
359HRESULT UefiVariableStore::queryVariables(std::vector<com::Utf8Str> &aNames,
360 std::vector<com::Guid> &aOwnerUuids)
361{
362 /* the machine needs to be mutable */
363 AutoMutableStateDependency adep(m->pMachine);
364 if (FAILED(adep.rc())) return adep.rc();
365
366 HRESULT hrc = i_retainUefiVariableStore(true /*fReadonly*/);
367 if (FAILED(hrc)) return hrc;
368
369 AutoReadLock rlock(this COMMA_LOCKVAL_SRC_POS);
370
371 RTVFSDIR hVfsDir = NIL_RTVFSDIR;
372 int vrc = RTVfsDirOpen(m->hVfsUefiVarStore, "by-name", 0 /*fFlags*/, &hVfsDir);
373 if (RT_SUCCESS(vrc))
374 {
375 RTDIRENTRYEX DirEntry;
376
377 vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
378 for (;;)
379 {
380 RTUUID OwnerUuid;
381 vrc = i_uefiVarStoreQueryVarOwnerUuid(DirEntry.szName, &OwnerUuid);
382 if (RT_FAILURE(vrc))
383 break;
384
385 aNames.push_back(Utf8Str(DirEntry.szName));
386 aOwnerUuids.push_back(com::Guid(OwnerUuid));
387
388 vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
389 if (RT_FAILURE(vrc))
390 break;
391 }
392
393 if (vrc == VERR_NO_MORE_FILES)
394 vrc = VINF_SUCCESS;
395
396 RTVfsDirRelease(hVfsDir);
397 }
398
399 i_releaseUefiVariableStore();
400
401 if (RT_FAILURE(vrc))
402 return setError(VBOX_E_IPRT_ERROR, tr("Failed to query the variables: %Rrc"), vrc);
403
404 return S_OK;
405}
406
407
408HRESULT UefiVariableStore::enrollOraclePlatformKey(void)
409{
410 /* the machine needs to be mutable */
411 AutoMutableStateDependency adep(m->pMachine);
412 if (FAILED(adep.rc())) return adep.rc();
413
414 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
415 if (FAILED(hrc)) return hrc;
416
417 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
418
419 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
420
421 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
422 EFI_GUID GuidOwnerVBox = EFI_SIGNATURE_OWNER_GUID_VBOX;
423 RTUUID UuidVBox;
424 RTEfiGuidToUuid(&UuidVBox, &GuidOwnerVBox);
425
426 const com::Guid GuidVBox(UuidVBox);
427
428 hrc = i_uefiVarStoreAddSignatureToDb(&GuidGlobalVar, "PK", g_abUefiOracleDefPk, g_cbUefiOracleDefPk,
429 GuidVBox, SignatureType_X509);
430
431 i_releaseUefiVariableStore();
432 return hrc;
433}
434
435
436HRESULT UefiVariableStore::enrollPlatformKey(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid)
437{
438 /* the machine needs to be mutable */
439 AutoMutableStateDependency adep(m->pMachine);
440 if (FAILED(adep.rc())) return adep.rc();
441
442 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
443 if (FAILED(hrc)) return hrc;
444
445 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
446
447 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
448 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "PK", aData, aOwnerUuid, SignatureType_X509);
449
450 i_releaseUefiVariableStore();
451 return hrc;
452}
453
454
455HRESULT UefiVariableStore::addKek(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
456{
457 /* the machine needs to be mutable */
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 GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
467 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "KEK", aData, aOwnerUuid, enmSignatureType);
468
469 i_releaseUefiVariableStore();
470 return hrc;
471}
472
473
474HRESULT UefiVariableStore::addSignatureToDb(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
475{
476 /* the machine needs to be mutable */
477 AutoMutableStateDependency adep(m->pMachine);
478 if (FAILED(adep.rc())) return adep.rc();
479
480 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
481 if (FAILED(hrc)) return hrc;
482
483 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
484
485 EFI_GUID GuidSecurityDb = EFI_GLOBAL_VARIABLE_GUID;
486 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "db", aData, aOwnerUuid, enmSignatureType);
487
488 i_releaseUefiVariableStore();
489 return hrc;
490}
491
492
493HRESULT UefiVariableStore::addSignatureToDbx(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
494{
495 /* the machine needs to be mutable */
496 AutoMutableStateDependency adep(m->pMachine);
497 if (FAILED(adep.rc())) return adep.rc();
498
499 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
500 if (FAILED(hrc)) return hrc;
501
502 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
503
504 EFI_GUID GuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
505 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "dbx", aData, aOwnerUuid, enmSignatureType);
506
507 i_releaseUefiVariableStore();
508 return hrc;
509}
510
511
512HRESULT UefiVariableStore::enrollDefaultMsSignatures(void)
513{
514 AutoMutableStateDependency adep(m->pMachine);
515 if (FAILED(adep.rc())) return adep.rc();
516
517 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
518 if (FAILED(hrc)) return hrc;
519
520 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
521
522 EFI_GUID EfiGuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
523 EFI_GUID EfiGuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
524
525 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
526 EFI_GUID EfiGuidMs = EFI_SIGNATURE_OWNER_GUID_MICROSOFT;
527 RTUUID UuidMs;
528 RTEfiGuidToUuid(&UuidMs, &EfiGuidMs);
529
530 const com::Guid GuidMs(UuidMs);
531
532 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidGlobalVar, "KEK", g_abUefiMicrosoftKek, g_cbUefiMicrosoftKek,
533 GuidMs, SignatureType_X509);
534 if (SUCCEEDED(hrc))
535 {
536 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftCa, g_cbUefiMicrosoftCa,
537 GuidMs, SignatureType_X509);
538 if (SUCCEEDED(hrc))
539 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftProPca, g_cbUefiMicrosoftProPca,
540 GuidMs, SignatureType_X509);
541 }
542
543 i_releaseUefiVariableStore();
544 return hrc;
545}
546
547
548/**
549 * Sets the given attributes for the given EFI variable store variable.
550 *
551 * @returns IPRT status code.
552 * @param pszVar The variable to set the attributes for.
553 * @param fAttr The attributes to set, see EFI_VAR_HEADER_ATTR_XXX.
554 */
555int UefiVariableStore::i_uefiVarStoreSetVarAttr(const char *pszVar, uint32_t fAttr)
556{
557 char szVarPath[_1K];
558 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
559 Assert(cch > 0); RT_NOREF(cch);
560
561 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
562 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
563 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
564 &hVfsFileAttr);
565 if (RT_SUCCESS(vrc))
566 {
567 uint32_t fAttrLe = RT_H2LE_U32(fAttr);
568 vrc = RTVfsFileWrite(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbWritten*/);
569 RTVfsFileRelease(hVfsFileAttr);
570 }
571
572 return vrc;
573}
574
575
576/**
577 * Queries the attributes for the given EFI variable store variable.
578 *
579 * @returns IPRT status code.
580 * @param pszVar The variable to query the attributes for.
581 * @param pfAttr Where to store the attributes on success.
582 */
583int UefiVariableStore::i_uefiVarStoreQueryVarAttr(const char *pszVar, uint32_t *pfAttr)
584{
585 char szVarPath[_1K];
586 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
587 Assert(cch > 0); RT_NOREF(cch);
588
589 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
590 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
591 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
592 &hVfsFileAttr);
593 if (RT_SUCCESS(vrc))
594 {
595 uint32_t fAttrLe = 0;
596 vrc = RTVfsFileRead(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbRead*/);
597 RTVfsFileRelease(hVfsFileAttr);
598 if (RT_SUCCESS(vrc))
599 *pfAttr = RT_LE2H_U32(fAttrLe);
600 }
601
602 return vrc;
603}
604
605
606/**
607 * Queries the data size for the given variable.
608 *
609 * @returns IPRT status code.
610 * @param pszVar The variable to query the size for.
611 * @param pcbVar Where to store the size of the variable data on success.
612 */
613int UefiVariableStore::i_uefiVarStoreQueryVarSz(const char *pszVar, uint64_t *pcbVar)
614{
615 char szVarPath[_1K];
616 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
617 Assert(cch > 0); RT_NOREF(cch);
618
619 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
620 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
621 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
622 &hVfsFile);
623 if (RT_SUCCESS(vrc))
624 {
625 vrc = RTVfsFileQuerySize(hVfsFile, pcbVar);
626 RTVfsFileRelease(hVfsFile);
627 }
628 else if (vrc == VERR_PATH_NOT_FOUND)
629 vrc = VERR_FILE_NOT_FOUND;
630
631 return vrc;
632}
633
634
635/**
636 * Returns the owner UUID of the given variable.
637 *
638 * @returns IPRT status code.
639 * @param pszVar The variable to query the owner UUID for.
640 * @param pUuid Where to store the owner UUID on success.
641 */
642int UefiVariableStore::i_uefiVarStoreQueryVarOwnerUuid(const char *pszVar, PRTUUID pUuid)
643{
644 char szVarPath[_1K];
645 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/uuid", pszVar);
646 Assert(cch > 0); RT_NOREF(cch);
647
648 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
649 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
650 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
651 &hVfsFileAttr);
652 if (RT_SUCCESS(vrc))
653 {
654 EFI_GUID OwnerGuid;
655 vrc = RTVfsFileRead(hVfsFileAttr, &OwnerGuid, sizeof(OwnerGuid), NULL /*pcbRead*/);
656 RTVfsFileRelease(hVfsFileAttr);
657 if (RT_SUCCESS(vrc))
658 RTEfiGuidToUuid(pUuid, &OwnerGuid);
659 }
660
661 return vrc;
662}
663
664
665/**
666 * Converts the given vector of variables attributes to a bitmask used internally.
667 *
668 * @returns Mask of UEFI variable attributes.
669 * @param vecAttributes Vector of variable atttributes.
670 */
671uint32_t UefiVariableStore::i_uefiVarAttrToMask(const std::vector<UefiVariableAttributes_T> &vecAttributes)
672{
673 uint32_t fAttr = 0;
674
675 for (size_t i = 0; i < vecAttributes.size(); i++)
676 fAttr |= (ULONG)vecAttributes[i];
677
678 return fAttr;
679}
680
681
682/**
683 * Converts the given aatribute mask to the attribute vector used externally.
684 *
685 * @returns nothing.
686 * @param fAttr The attribute mask.
687 * @param aAttributes The vector to store the attibutes in.
688 */
689void UefiVariableStore::i_uefiAttrMaskToVec(uint32_t fAttr, std::vector<UefiVariableAttributes_T> &aAttributes)
690{
691 if (fAttr & EFI_VAR_HEADER_ATTR_NON_VOLATILE)
692 aAttributes.push_back(UefiVariableAttributes_NonVolatile);
693 if (fAttr & EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS)
694 aAttributes.push_back(UefiVariableAttributes_BootServiceAccess);
695 if (fAttr & EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS)
696 aAttributes.push_back(UefiVariableAttributes_RuntimeAccess);
697 if (fAttr & EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD)
698 aAttributes.push_back(UefiVariableAttributes_HwErrorRecord);
699 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS)
700 aAttributes.push_back(UefiVariableAttributes_AuthWriteAccess);
701 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS)
702 aAttributes.push_back(UefiVariableAttributes_AuthTimeBasedWriteAccess);
703 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE)
704 aAttributes.push_back(UefiVariableAttributes_AuthAppendWrite);
705}
706
707
708/**
709 * Retains the reference of the variable store from the parent.
710 *
711 * @returns COM status code.
712 * @param fReadonly Flag whether the access is readonly.
713 */
714HRESULT UefiVariableStore::i_retainUefiVariableStore(bool fReadonly)
715{
716 Assert(m->hVfsUefiVarStore = NIL_RTVFS);
717 return m->pParent->i_retainUefiVarStore(&m->hVfsUefiVarStore, fReadonly);
718}
719
720
721/**
722 * Releases the reference of the variable store from the parent.
723 *
724 * @returns COM status code.
725 */
726HRESULT UefiVariableStore::i_releaseUefiVariableStore(void)
727{
728 RTVFS hVfs = m->hVfsUefiVarStore;
729
730 m->hVfsUefiVarStore = NIL_RTVFS;
731 return m->pParent->i_releaseUefiVarStore(hVfs);
732}
733
734
735/**
736 * Adds the given variable to the variable store.
737 *
738 * @returns IPRT status code.
739 * @param pGuid The EFI GUID of the variable.
740 * @param pszVar The variable name.
741 * @param fAttr Attributes for the variable.
742 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
743 */
744HRESULT UefiVariableStore::i_uefiVarStoreAddVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, PRTVFSFILE phVfsFile)
745{
746 RTUUID UuidVar;
747 RTEfiGuidToUuid(&UuidVar, pGuid);
748
749 char szVarPath[_1K];
750 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-uuid/%RTuuid/%s", &UuidVar, pszVar);
751 Assert(cch > 0); RT_NOREF(cch);
752
753 HRESULT hrc = S_OK;
754 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
755 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
756 phVfsFile);
757 if ( vrc == VERR_PATH_NOT_FOUND
758 || vrc == VERR_FILE_NOT_FOUND)
759 {
760 /*
761 * Try to create the owner GUID of the variable by creating the appropriate directory,
762 * ignore error if it exists already.
763 */
764 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
765 vrc = RTVfsOpenRoot(m->hVfsUefiVarStore, &hVfsDirRoot);
766 if (RT_SUCCESS(vrc))
767 {
768 char szGuidPath[_1K];
769 cch = RTStrPrintf2(szGuidPath, sizeof(szGuidPath), "by-uuid/%RTuuid", &UuidVar);
770 Assert(cch > 0);
771
772 RTVFSDIR hVfsDirGuid = NIL_RTVFSDIR;
773 vrc = RTVfsDirCreateDir(hVfsDirRoot, szGuidPath, 0755, 0 /*fFlags*/, &hVfsDirGuid);
774 if (RT_SUCCESS(vrc))
775 RTVfsDirRelease(hVfsDirGuid);
776 else if (vrc == VERR_ALREADY_EXISTS)
777 vrc = VINF_SUCCESS;
778
779 RTVfsDirRelease(hVfsDirRoot);
780 }
781 else
782 hrc = setError(E_FAIL, tr("Opening variable storage root directory failed: %Rrc"), vrc);
783
784 if (RT_SUCCESS(vrc))
785 {
786 vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
787 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE,
788 phVfsFile);
789 if (RT_SUCCESS(vrc))
790 vrc = i_uefiVarStoreSetVarAttr(pszVar, fAttr);
791 }
792
793 if (RT_FAILURE(vrc))
794 hrc = setError(E_FAIL, tr("Creating the variable '%s' failed: %Rrc"), pszVar, vrc);
795 }
796
797 return hrc;
798}
799
800
801/**
802 * Tries to open the given variable from the variable store and returns a file handle.
803 *
804 * @returns IPRT status code.
805 * @param pszVar The variable name.
806 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
807 */
808HRESULT UefiVariableStore::i_uefiVarStoreOpenVar(const char *pszVar, PRTVFSFILE phVfsFile)
809{
810 char szVarPath[_1K];
811 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
812 Assert(cch > 0); RT_NOREF(cch);
813
814 HRESULT hrc = S_OK;
815 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
816 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
817 phVfsFile);
818 if ( vrc == VERR_PATH_NOT_FOUND
819 || vrc == VERR_FILE_NOT_FOUND)
820 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The variable '%s' could not be found"), pszVar);
821 else if (RT_FAILURE(vrc))
822 hrc = setError(VBOX_E_IPRT_ERROR, tr("Couldn't open variable '%s' (%Rrc)"), pszVar, vrc);
823
824 return hrc;
825}
826
827
828HRESULT UefiVariableStore::i_uefiVarStoreSetVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, const void *pvData, size_t cbData)
829{
830 RTVFSFILE hVfsFileVar = NIL_RTVFSFILE;
831
832 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszVar, fAttr, &hVfsFileVar);
833 if (SUCCEEDED(hrc))
834 {
835 int vrc = RTVfsFileWrite(hVfsFileVar, pvData, cbData, NULL /*pcbWritten*/);
836 if (RT_FAILURE(vrc))
837 hrc = setError(E_FAIL, tr("Setting the variable '%s' failed: %Rrc"), pszVar, vrc);
838
839 RTVfsFileRelease(hVfsFileVar);
840 }
841
842 return hrc;
843}
844
845
846HRESULT UefiVariableStore::i_uefiVarStoreQueryVar(const char *pszVar, void *pvData, size_t cbData)
847{
848 HRESULT hrc = S_OK;
849
850 char szVarPath[_1K];
851 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
852 Assert(cch > 0); RT_NOREF(cch);
853
854 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
855 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
856 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
857 &hVfsFile);
858 if (RT_SUCCESS(vrc))
859 {
860 vrc = RTVfsFileRead(hVfsFile, pvData, cbData, NULL /*pcbRead*/);
861 if (RT_FAILURE(vrc))
862 hrc = setError(E_FAIL, tr("Failed to read data of variable '%s': %Rrc"), pszVar, vrc);
863
864 RTVfsFileRelease(hVfsFile);
865 }
866 else
867 hrc = setError(E_FAIL, tr("Failed to open variable '%s' for reading: %Rrc"), pszVar, vrc);
868
869 return hrc;
870}
871
872HRESULT UefiVariableStore::i_uefiSigDbAddSig(RTEFISIGDB hEfiSigDb, const void *pvData, size_t cbData,
873 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
874{
875 RTEFISIGTYPE enmSigType = RTEFISIGTYPE_INVALID;
876
877 switch (enmSignatureType)
878 {
879 case SignatureType_X509:
880 enmSigType = RTEFISIGTYPE_X509;
881 break;
882 case SignatureType_Sha256:
883 enmSigType = RTEFISIGTYPE_SHA256;
884 break;
885 default:
886 return setError(E_FAIL, tr("The given signature type is not supported"));
887 }
888
889 int vrc = RTEfiSigDbAddSignatureFromBuf(hEfiSigDb, enmSigType, aOwnerUuid.raw(), pvData, cbData);
890 if (RT_SUCCESS(vrc))
891 return S_OK;
892
893 return setError(E_FAIL, tr("Failed to add signature to the database (%Rrc)"), vrc);
894}
895
896
897HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDb(PCEFI_GUID pGuid, const char *pszDb, const void *pvData, size_t cbData,
898 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
899{
900 RTVFSFILE hVfsFileSigDb = NIL_RTVFSFILE;
901
902 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszDb,
903 EFI_VAR_HEADER_ATTR_NON_VOLATILE
904 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
905 | EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS
906 | EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS,
907 &hVfsFileSigDb);
908 if (SUCCEEDED(hrc))
909 {
910 RTEFISIGDB hEfiSigDb;
911
912 int vrc = RTEfiSigDbCreate(&hEfiSigDb);
913 if (RT_SUCCESS(vrc))
914 {
915 vrc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFileSigDb);
916 if (RT_SUCCESS(vrc))
917 {
918 hrc = i_uefiSigDbAddSig(hEfiSigDb, pvData, cbData, aOwnerUuid, enmSignatureType);
919 if (SUCCEEDED(hrc))
920 {
921 vrc = RTVfsFileSeek(hVfsFileSigDb, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
922 AssertRC(vrc);
923
924 vrc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFileSigDb);
925 if (RT_FAILURE(vrc))
926 hrc = setError(E_FAIL, tr("Writing updated signature database failed: %Rrc"), vrc);
927 }
928 }
929 else
930 hrc = setError(E_FAIL, tr("Loading signature database failed: %Rrc"), vrc);
931
932 RTEfiSigDbDestroy(hEfiSigDb);
933 }
934 else
935 hrc = setError(E_FAIL, tr("Creating signature database failed: %Rrc"), vrc);
936
937 RTVfsFileRelease(hVfsFileSigDb);
938 }
939
940 return hrc;
941}
942
943
944HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDbVec(PCEFI_GUID pGuid, const char *pszDb, const std::vector<BYTE> &aData,
945 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
946{
947 return i_uefiVarStoreAddSignatureToDb(pGuid, pszDb, &aData.front(), aData.size(), aOwnerUuid, enmSignatureType);
948}
949
950/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use