VirtualBox

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

Last change on this file since 100078 was 99739, checked in by vboxsync, 13 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.5 KB
Line 
1/* $Id: UefiVariableStoreImpl.cpp 99739 2023-05-11 01:01:08Z 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 /* the machine needs to be mutable */
155 AutoMutableStateDependency adep(m->pMachine);
156 if (FAILED(adep.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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.hrc())) return adep.hrc();
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
558HRESULT UefiVariableStore::addSignatureToMok(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
559{
560 /* the machine needs to be mutable */
561 AutoMutableStateDependency adep(m->pMachine);
562 if (FAILED(adep.hrc())) return adep.hrc();
563
564 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
565 if (FAILED(hrc)) return hrc;
566
567 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
568
569 EFI_GUID GuidMokList = EFI_IMAGE_MOK_DATABASE_GUID;
570 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidMokList, "MokList", aData, aOwnerUuid, enmSignatureType, false /*fRuntime*/);
571
572 i_releaseUefiVariableStore();
573 return hrc;
574}
575
576
577
578
579/**
580 * Sets the given attributes for the given EFI variable store variable.
581 *
582 * @returns IPRT status code.
583 * @param pszVar The variable to set the attributes for.
584 * @param fAttr The attributes to set, see EFI_VAR_HEADER_ATTR_XXX.
585 */
586int UefiVariableStore::i_uefiVarStoreSetVarAttr(const char *pszVar, uint32_t fAttr)
587{
588 char szVarPath[_1K];
589 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
590 Assert(cch > 0); RT_NOREF(cch);
591
592 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
593 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
594 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
595 &hVfsFileAttr);
596 if (RT_SUCCESS(vrc))
597 {
598 uint32_t fAttrLe = RT_H2LE_U32(fAttr);
599 vrc = RTVfsFileWrite(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbWritten*/);
600 RTVfsFileRelease(hVfsFileAttr);
601 }
602
603 return vrc;
604}
605
606
607/**
608 * Queries the attributes for the given EFI variable store variable.
609 *
610 * @returns IPRT status code.
611 * @param pszVar The variable to query the attributes for.
612 * @param pfAttr Where to store the attributes on success.
613 */
614int UefiVariableStore::i_uefiVarStoreQueryVarAttr(const char *pszVar, uint32_t *pfAttr)
615{
616 char szVarPath[_1K];
617 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
618 Assert(cch > 0); RT_NOREF(cch);
619
620 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
621 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
622 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
623 &hVfsFileAttr);
624 if (RT_SUCCESS(vrc))
625 {
626 uint32_t fAttrLe = 0;
627 vrc = RTVfsFileRead(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbRead*/);
628 RTVfsFileRelease(hVfsFileAttr);
629 if (RT_SUCCESS(vrc))
630 *pfAttr = RT_LE2H_U32(fAttrLe);
631 }
632
633 return vrc;
634}
635
636
637/**
638 * Queries the data size for the given variable.
639 *
640 * @returns IPRT status code.
641 * @param pszVar The variable to query the size for.
642 * @param pcbVar Where to store the size of the variable data on success.
643 */
644int UefiVariableStore::i_uefiVarStoreQueryVarSz(const char *pszVar, uint64_t *pcbVar)
645{
646 char szVarPath[_1K];
647 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
648 Assert(cch > 0); RT_NOREF(cch);
649
650 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
651 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
652 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
653 &hVfsFile);
654 if (RT_SUCCESS(vrc))
655 {
656 vrc = RTVfsFileQuerySize(hVfsFile, pcbVar);
657 RTVfsFileRelease(hVfsFile);
658 }
659 else if (vrc == VERR_PATH_NOT_FOUND)
660 vrc = VERR_FILE_NOT_FOUND;
661
662 return vrc;
663}
664
665
666/**
667 * Returns the owner UUID of the given variable.
668 *
669 * @returns IPRT status code.
670 * @param pszVar The variable to query the owner UUID for.
671 * @param pUuid Where to store the owner UUID on success.
672 */
673int UefiVariableStore::i_uefiVarStoreQueryVarOwnerUuid(const char *pszVar, PRTUUID pUuid)
674{
675 char szVarPath[_1K];
676 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/uuid", pszVar);
677 Assert(cch > 0); RT_NOREF(cch);
678
679 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
680 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
681 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
682 &hVfsFileAttr);
683 if (RT_SUCCESS(vrc))
684 {
685 EFI_GUID OwnerGuid;
686 vrc = RTVfsFileRead(hVfsFileAttr, &OwnerGuid, sizeof(OwnerGuid), NULL /*pcbRead*/);
687 RTVfsFileRelease(hVfsFileAttr);
688 if (RT_SUCCESS(vrc))
689 RTEfiGuidToUuid(pUuid, &OwnerGuid);
690 }
691
692 return vrc;
693}
694
695
696/**
697 * Converts the given vector of variables attributes to a bitmask used internally.
698 *
699 * @returns Mask of UEFI variable attributes.
700 * @param vecAttributes Vector of variable atttributes.
701 */
702uint32_t UefiVariableStore::i_uefiVarAttrToMask(const std::vector<UefiVariableAttributes_T> &vecAttributes)
703{
704 uint32_t fAttr = 0;
705
706 for (size_t i = 0; i < vecAttributes.size(); i++)
707 fAttr |= (ULONG)vecAttributes[i];
708
709 return fAttr;
710}
711
712
713/**
714 * Converts the given aatribute mask to the attribute vector used externally.
715 *
716 * @param fAttr The attribute mask.
717 * @param aAttributes The vector to store the attibutes in.
718 */
719void UefiVariableStore::i_uefiAttrMaskToVec(uint32_t fAttr, std::vector<UefiVariableAttributes_T> &aAttributes)
720{
721 if (fAttr & EFI_VAR_HEADER_ATTR_NON_VOLATILE)
722 aAttributes.push_back(UefiVariableAttributes_NonVolatile);
723 if (fAttr & EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS)
724 aAttributes.push_back(UefiVariableAttributes_BootServiceAccess);
725 if (fAttr & EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS)
726 aAttributes.push_back(UefiVariableAttributes_RuntimeAccess);
727 if (fAttr & EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD)
728 aAttributes.push_back(UefiVariableAttributes_HwErrorRecord);
729 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS)
730 aAttributes.push_back(UefiVariableAttributes_AuthWriteAccess);
731 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS)
732 aAttributes.push_back(UefiVariableAttributes_AuthTimeBasedWriteAccess);
733 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE)
734 aAttributes.push_back(UefiVariableAttributes_AuthAppendWrite);
735}
736
737
738/**
739 * Retains the reference of the variable store from the parent.
740 *
741 * @returns COM status code.
742 * @param fReadonly Flag whether the access is readonly.
743 */
744HRESULT UefiVariableStore::i_retainUefiVariableStore(bool fReadonly)
745{
746 Assert(m->hVfsUefiVarStore = NIL_RTVFS);
747 return m->pParent->i_retainUefiVarStore(&m->hVfsUefiVarStore, fReadonly);
748}
749
750
751/**
752 * Releases the reference of the variable store from the parent.
753 *
754 * @returns COM status code.
755 */
756HRESULT UefiVariableStore::i_releaseUefiVariableStore(void)
757{
758 RTVFS hVfs = m->hVfsUefiVarStore;
759
760 m->hVfsUefiVarStore = NIL_RTVFS;
761 return m->pParent->i_releaseUefiVarStore(hVfs);
762}
763
764
765/**
766 * Adds the given variable to the variable store.
767 *
768 * @returns IPRT status code.
769 * @param pGuid The EFI GUID of the variable.
770 * @param pszVar The variable name.
771 * @param fAttr Attributes for the variable.
772 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
773 */
774HRESULT UefiVariableStore::i_uefiVarStoreAddVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, PRTVFSFILE phVfsFile)
775{
776 RTUUID UuidVar;
777 RTEfiGuidToUuid(&UuidVar, pGuid);
778
779 char szVarPath[_1K];
780 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-uuid/%RTuuid/%s", &UuidVar, pszVar);
781 Assert(cch > 0); RT_NOREF(cch);
782
783 HRESULT hrc = S_OK;
784 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
785 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
786 phVfsFile);
787 if ( vrc == VERR_PATH_NOT_FOUND
788 || vrc == VERR_FILE_NOT_FOUND)
789 {
790 /*
791 * Try to create the owner GUID of the variable by creating the appropriate directory,
792 * ignore error if it exists already.
793 */
794 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
795 vrc = RTVfsOpenRoot(m->hVfsUefiVarStore, &hVfsDirRoot);
796 if (RT_SUCCESS(vrc))
797 {
798 char szGuidPath[_1K];
799 cch = RTStrPrintf2(szGuidPath, sizeof(szGuidPath), "by-uuid/%RTuuid", &UuidVar);
800 Assert(cch > 0);
801
802 RTVFSDIR hVfsDirGuid = NIL_RTVFSDIR;
803 vrc = RTVfsDirCreateDir(hVfsDirRoot, szGuidPath, 0755, 0 /*fFlags*/, &hVfsDirGuid);
804 if (RT_SUCCESS(vrc))
805 RTVfsDirRelease(hVfsDirGuid);
806 else if (vrc == VERR_ALREADY_EXISTS)
807 vrc = VINF_SUCCESS;
808
809 RTVfsDirRelease(hVfsDirRoot);
810 }
811 else
812 hrc = setError(E_FAIL, tr("Opening variable storage root directory failed: %Rrc"), vrc);
813
814 if (RT_SUCCESS(vrc))
815 {
816 vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
817 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE,
818 phVfsFile);
819 if (RT_SUCCESS(vrc))
820 vrc = i_uefiVarStoreSetVarAttr(pszVar, fAttr);
821 }
822
823 if (RT_FAILURE(vrc))
824 hrc = setError(E_FAIL, tr("Creating the variable '%s' failed: %Rrc"), pszVar, vrc);
825 }
826
827 return hrc;
828}
829
830
831/**
832 * Tries to open the given variable from the variable store and returns a file handle.
833 *
834 * @returns IPRT status code.
835 * @param pszVar The variable name.
836 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
837 */
838HRESULT UefiVariableStore::i_uefiVarStoreOpenVar(const char *pszVar, PRTVFSFILE phVfsFile)
839{
840 char szVarPath[_1K];
841 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
842 Assert(cch > 0); RT_NOREF(cch);
843
844 HRESULT hrc = S_OK;
845 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
846 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
847 phVfsFile);
848 if ( vrc == VERR_PATH_NOT_FOUND
849 || vrc == VERR_FILE_NOT_FOUND)
850 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The variable '%s' could not be found"), pszVar);
851 else if (RT_FAILURE(vrc))
852 hrc = setError(VBOX_E_IPRT_ERROR, tr("Couldn't open variable '%s' (%Rrc)"), pszVar, vrc);
853
854 return hrc;
855}
856
857
858HRESULT UefiVariableStore::i_uefiVarStoreSetVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, const void *pvData, size_t cbData)
859{
860 RTVFSFILE hVfsFileVar = NIL_RTVFSFILE;
861
862 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszVar, fAttr, &hVfsFileVar);
863 if (SUCCEEDED(hrc))
864 {
865 int vrc = RTVfsFileWrite(hVfsFileVar, pvData, cbData, NULL /*pcbWritten*/);
866 if (RT_FAILURE(vrc))
867 hrc = setError(E_FAIL, tr("Setting the variable '%s' failed: %Rrc"), pszVar, vrc);
868
869 RTVfsFileRelease(hVfsFileVar);
870 }
871
872 return hrc;
873}
874
875
876HRESULT UefiVariableStore::i_uefiVarStoreQueryVar(const char *pszVar, void *pvData, size_t cbData)
877{
878 HRESULT hrc = S_OK;
879
880 char szVarPath[_1K];
881 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
882 Assert(cch > 0); RT_NOREF(cch);
883
884 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
885 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
886 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
887 &hVfsFile);
888 if (RT_SUCCESS(vrc))
889 {
890 vrc = RTVfsFileRead(hVfsFile, pvData, cbData, NULL /*pcbRead*/);
891 if (RT_FAILURE(vrc))
892 hrc = setError(E_FAIL, tr("Failed to read data of variable '%s': %Rrc"), pszVar, vrc);
893
894 RTVfsFileRelease(hVfsFile);
895 }
896 else
897 hrc = setError(E_FAIL, tr("Failed to open variable '%s' for reading: %Rrc"), pszVar, vrc);
898
899 return hrc;
900}
901
902HRESULT UefiVariableStore::i_uefiSigDbAddSig(RTEFISIGDB hEfiSigDb, const void *pvData, size_t cbData,
903 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
904{
905 RTEFISIGTYPE enmSigType = RTEFISIGTYPE_INVALID;
906
907 switch (enmSignatureType)
908 {
909 case SignatureType_X509:
910 enmSigType = RTEFISIGTYPE_X509;
911 break;
912 case SignatureType_Sha256:
913 enmSigType = RTEFISIGTYPE_SHA256;
914 break;
915 default:
916 return setError(E_FAIL, tr("The given signature type is not supported"));
917 }
918
919 int vrc = RTEfiSigDbAddSignatureFromBuf(hEfiSigDb, enmSigType, aOwnerUuid.raw(), pvData, cbData);
920 if (RT_SUCCESS(vrc))
921 return S_OK;
922
923 return setError(E_FAIL, tr("Failed to add signature to the database (%Rrc)"), vrc);
924}
925
926
927HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDb(PCEFI_GUID pGuid, const char *pszDb, const void *pvData, size_t cbData,
928 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType, bool fRuntime)
929{
930 RTVFSFILE hVfsFileSigDb = NIL_RTVFSFILE;
931
932 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszDb,
933 EFI_VAR_HEADER_ATTR_NON_VOLATILE
934 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
935 | (fRuntime ? EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS : 0)
936 | EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS,
937 &hVfsFileSigDb);
938 if (SUCCEEDED(hrc))
939 {
940 RTEFISIGDB hEfiSigDb;
941
942 int vrc = RTEfiSigDbCreate(&hEfiSigDb);
943 if (RT_SUCCESS(vrc))
944 {
945 vrc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFileSigDb);
946 if (RT_SUCCESS(vrc))
947 {
948 hrc = i_uefiSigDbAddSig(hEfiSigDb, pvData, cbData, aOwnerUuid, enmSignatureType);
949 if (SUCCEEDED(hrc))
950 {
951 vrc = RTVfsFileSeek(hVfsFileSigDb, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
952 AssertRC(vrc);
953
954 vrc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFileSigDb);
955 if (RT_FAILURE(vrc))
956 hrc = setError(E_FAIL, tr("Writing updated signature database failed: %Rrc"), vrc);
957 }
958 }
959 else
960 hrc = setError(E_FAIL, tr("Loading signature database failed: %Rrc"), vrc);
961
962 RTEfiSigDbDestroy(hEfiSigDb);
963 }
964 else
965 hrc = setError(E_FAIL, tr("Creating signature database failed: %Rrc"), vrc);
966
967 RTVfsFileRelease(hVfsFileSigDb);
968 }
969
970 return hrc;
971}
972
973
974HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDbVec(PCEFI_GUID pGuid, const char *pszDb, const std::vector<BYTE> &aData,
975 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType, bool fRuntime)
976{
977 return i_uefiVarStoreAddSignatureToDb(pGuid, pszDb, &aData.front(), aData.size(), aOwnerUuid, enmSignatureType, fRuntime);
978}
979
980/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use