VirtualBox

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

Last change on this file since 99599 was 98965, checked in by vboxsync, 20 months ago

Main/UefiVairableStore: The shim parsing the MokList rejects it due to EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS being set, bugref:10287

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.6 KB
Line 
1/* $Id: UefiVariableStoreImpl.cpp 98965 2023-03-14 15:47:35Z 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 * @returns nothing.
717 * @param fAttr The attribute mask.
718 * @param aAttributes The vector to store the attibutes in.
719 */
720void UefiVariableStore::i_uefiAttrMaskToVec(uint32_t fAttr, std::vector<UefiVariableAttributes_T> &aAttributes)
721{
722 if (fAttr & EFI_VAR_HEADER_ATTR_NON_VOLATILE)
723 aAttributes.push_back(UefiVariableAttributes_NonVolatile);
724 if (fAttr & EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS)
725 aAttributes.push_back(UefiVariableAttributes_BootServiceAccess);
726 if (fAttr & EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS)
727 aAttributes.push_back(UefiVariableAttributes_RuntimeAccess);
728 if (fAttr & EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD)
729 aAttributes.push_back(UefiVariableAttributes_HwErrorRecord);
730 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS)
731 aAttributes.push_back(UefiVariableAttributes_AuthWriteAccess);
732 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS)
733 aAttributes.push_back(UefiVariableAttributes_AuthTimeBasedWriteAccess);
734 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE)
735 aAttributes.push_back(UefiVariableAttributes_AuthAppendWrite);
736}
737
738
739/**
740 * Retains the reference of the variable store from the parent.
741 *
742 * @returns COM status code.
743 * @param fReadonly Flag whether the access is readonly.
744 */
745HRESULT UefiVariableStore::i_retainUefiVariableStore(bool fReadonly)
746{
747 Assert(m->hVfsUefiVarStore = NIL_RTVFS);
748 return m->pParent->i_retainUefiVarStore(&m->hVfsUefiVarStore, fReadonly);
749}
750
751
752/**
753 * Releases the reference of the variable store from the parent.
754 *
755 * @returns COM status code.
756 */
757HRESULT UefiVariableStore::i_releaseUefiVariableStore(void)
758{
759 RTVFS hVfs = m->hVfsUefiVarStore;
760
761 m->hVfsUefiVarStore = NIL_RTVFS;
762 return m->pParent->i_releaseUefiVarStore(hVfs);
763}
764
765
766/**
767 * Adds the given variable to the variable store.
768 *
769 * @returns IPRT status code.
770 * @param pGuid The EFI GUID of the variable.
771 * @param pszVar The variable name.
772 * @param fAttr Attributes for the variable.
773 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
774 */
775HRESULT UefiVariableStore::i_uefiVarStoreAddVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, PRTVFSFILE phVfsFile)
776{
777 RTUUID UuidVar;
778 RTEfiGuidToUuid(&UuidVar, pGuid);
779
780 char szVarPath[_1K];
781 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-uuid/%RTuuid/%s", &UuidVar, pszVar);
782 Assert(cch > 0); RT_NOREF(cch);
783
784 HRESULT hrc = S_OK;
785 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
786 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
787 phVfsFile);
788 if ( vrc == VERR_PATH_NOT_FOUND
789 || vrc == VERR_FILE_NOT_FOUND)
790 {
791 /*
792 * Try to create the owner GUID of the variable by creating the appropriate directory,
793 * ignore error if it exists already.
794 */
795 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
796 vrc = RTVfsOpenRoot(m->hVfsUefiVarStore, &hVfsDirRoot);
797 if (RT_SUCCESS(vrc))
798 {
799 char szGuidPath[_1K];
800 cch = RTStrPrintf2(szGuidPath, sizeof(szGuidPath), "by-uuid/%RTuuid", &UuidVar);
801 Assert(cch > 0);
802
803 RTVFSDIR hVfsDirGuid = NIL_RTVFSDIR;
804 vrc = RTVfsDirCreateDir(hVfsDirRoot, szGuidPath, 0755, 0 /*fFlags*/, &hVfsDirGuid);
805 if (RT_SUCCESS(vrc))
806 RTVfsDirRelease(hVfsDirGuid);
807 else if (vrc == VERR_ALREADY_EXISTS)
808 vrc = VINF_SUCCESS;
809
810 RTVfsDirRelease(hVfsDirRoot);
811 }
812 else
813 hrc = setError(E_FAIL, tr("Opening variable storage root directory failed: %Rrc"), vrc);
814
815 if (RT_SUCCESS(vrc))
816 {
817 vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
818 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE,
819 phVfsFile);
820 if (RT_SUCCESS(vrc))
821 vrc = i_uefiVarStoreSetVarAttr(pszVar, fAttr);
822 }
823
824 if (RT_FAILURE(vrc))
825 hrc = setError(E_FAIL, tr("Creating the variable '%s' failed: %Rrc"), pszVar, vrc);
826 }
827
828 return hrc;
829}
830
831
832/**
833 * Tries to open the given variable from the variable store and returns a file handle.
834 *
835 * @returns IPRT status code.
836 * @param pszVar The variable name.
837 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
838 */
839HRESULT UefiVariableStore::i_uefiVarStoreOpenVar(const char *pszVar, PRTVFSFILE phVfsFile)
840{
841 char szVarPath[_1K];
842 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
843 Assert(cch > 0); RT_NOREF(cch);
844
845 HRESULT hrc = S_OK;
846 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
847 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
848 phVfsFile);
849 if ( vrc == VERR_PATH_NOT_FOUND
850 || vrc == VERR_FILE_NOT_FOUND)
851 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The variable '%s' could not be found"), pszVar);
852 else if (RT_FAILURE(vrc))
853 hrc = setError(VBOX_E_IPRT_ERROR, tr("Couldn't open variable '%s' (%Rrc)"), pszVar, vrc);
854
855 return hrc;
856}
857
858
859HRESULT UefiVariableStore::i_uefiVarStoreSetVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, const void *pvData, size_t cbData)
860{
861 RTVFSFILE hVfsFileVar = NIL_RTVFSFILE;
862
863 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszVar, fAttr, &hVfsFileVar);
864 if (SUCCEEDED(hrc))
865 {
866 int vrc = RTVfsFileWrite(hVfsFileVar, pvData, cbData, NULL /*pcbWritten*/);
867 if (RT_FAILURE(vrc))
868 hrc = setError(E_FAIL, tr("Setting the variable '%s' failed: %Rrc"), pszVar, vrc);
869
870 RTVfsFileRelease(hVfsFileVar);
871 }
872
873 return hrc;
874}
875
876
877HRESULT UefiVariableStore::i_uefiVarStoreQueryVar(const char *pszVar, void *pvData, size_t cbData)
878{
879 HRESULT hrc = S_OK;
880
881 char szVarPath[_1K];
882 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
883 Assert(cch > 0); RT_NOREF(cch);
884
885 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
886 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
887 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
888 &hVfsFile);
889 if (RT_SUCCESS(vrc))
890 {
891 vrc = RTVfsFileRead(hVfsFile, pvData, cbData, NULL /*pcbRead*/);
892 if (RT_FAILURE(vrc))
893 hrc = setError(E_FAIL, tr("Failed to read data of variable '%s': %Rrc"), pszVar, vrc);
894
895 RTVfsFileRelease(hVfsFile);
896 }
897 else
898 hrc = setError(E_FAIL, tr("Failed to open variable '%s' for reading: %Rrc"), pszVar, vrc);
899
900 return hrc;
901}
902
903HRESULT UefiVariableStore::i_uefiSigDbAddSig(RTEFISIGDB hEfiSigDb, const void *pvData, size_t cbData,
904 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
905{
906 RTEFISIGTYPE enmSigType = RTEFISIGTYPE_INVALID;
907
908 switch (enmSignatureType)
909 {
910 case SignatureType_X509:
911 enmSigType = RTEFISIGTYPE_X509;
912 break;
913 case SignatureType_Sha256:
914 enmSigType = RTEFISIGTYPE_SHA256;
915 break;
916 default:
917 return setError(E_FAIL, tr("The given signature type is not supported"));
918 }
919
920 int vrc = RTEfiSigDbAddSignatureFromBuf(hEfiSigDb, enmSigType, aOwnerUuid.raw(), pvData, cbData);
921 if (RT_SUCCESS(vrc))
922 return S_OK;
923
924 return setError(E_FAIL, tr("Failed to add signature to the database (%Rrc)"), vrc);
925}
926
927
928HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDb(PCEFI_GUID pGuid, const char *pszDb, const void *pvData, size_t cbData,
929 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType, bool fRuntime)
930{
931 RTVFSFILE hVfsFileSigDb = NIL_RTVFSFILE;
932
933 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszDb,
934 EFI_VAR_HEADER_ATTR_NON_VOLATILE
935 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
936 | (fRuntime ? EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS : 0)
937 | EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS,
938 &hVfsFileSigDb);
939 if (SUCCEEDED(hrc))
940 {
941 RTEFISIGDB hEfiSigDb;
942
943 int vrc = RTEfiSigDbCreate(&hEfiSigDb);
944 if (RT_SUCCESS(vrc))
945 {
946 vrc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFileSigDb);
947 if (RT_SUCCESS(vrc))
948 {
949 hrc = i_uefiSigDbAddSig(hEfiSigDb, pvData, cbData, aOwnerUuid, enmSignatureType);
950 if (SUCCEEDED(hrc))
951 {
952 vrc = RTVfsFileSeek(hVfsFileSigDb, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
953 AssertRC(vrc);
954
955 vrc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFileSigDb);
956 if (RT_FAILURE(vrc))
957 hrc = setError(E_FAIL, tr("Writing updated signature database failed: %Rrc"), vrc);
958 }
959 }
960 else
961 hrc = setError(E_FAIL, tr("Loading signature database failed: %Rrc"), vrc);
962
963 RTEfiSigDbDestroy(hEfiSigDb);
964 }
965 else
966 hrc = setError(E_FAIL, tr("Creating signature database failed: %Rrc"), vrc);
967
968 RTVfsFileRelease(hVfsFileSigDb);
969 }
970
971 return hrc;
972}
973
974
975HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDbVec(PCEFI_GUID pGuid, const char *pszDb, const std::vector<BYTE> &aData,
976 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType, bool fRuntime)
977{
978 return i_uefiVarStoreAddSignatureToDb(pGuid, pszDb, &aData.front(), aData.size(), aOwnerUuid, enmSignatureType, fRuntime);
979}
980
981/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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