VirtualBox

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

Last change on this file since 104793 was 104793, checked in by vboxsync, 11 months ago

Main: Add new Microsoft certs issued 2023 (KEK, Windows boot loader CA and 3rd party boot loader CA). Touch up the variable naming slightly to reflect the use of the certs in the DB better. Add a pointer where to get the certs (the github project has URLs which are the real authority). bugref:10699

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette