VirtualBox

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

Last change on this file since 97698 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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