VirtualBox

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

Last change on this file was 103532, checked in by vboxsync, 3 months ago

VBoxManage: Add subcommand for enabling UEFI secure boot (and show the status in the VM infos).
Main/NVRAMStore+UefiVariableStore: Tweaks to allow reading the UEFI secure boot state when the VM isn't mutable.
doc/manual: Update VBoxManage manpage.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use