VirtualBox

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

Last change on this file since 107597 was 107552, checked in by vboxsync, 3 weeks ago

Main/src-server/UefiVariableStoreImpl.cpp: Missing error check and add exception for debug only use of a variable, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.1 KB
Line 
1/* $Id: UefiVariableStoreImpl.cpp 107552 2025-01-09 08:37:51Z vboxsync $ */
2/** @file
3 * VirtualBox COM NVRAM store class implementation
4 */
5
6/*
7 * Copyright (C) 2021-2024 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 if (RT_SUCCESS(vrc))
377 {
378 for (;;)
379 {
380 RTUUID OwnerUuid;
381 vrc = i_uefiVarStoreQueryVarOwnerUuid(DirEntry.szName, &OwnerUuid);
382 if (RT_FAILURE(vrc))
383 break;
384
385 aNames.push_back(Utf8Str(DirEntry.szName));
386 aOwnerUuids.push_back(com::Guid(OwnerUuid));
387
388 vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, NULL, RTFSOBJATTRADD_NOTHING);
389 if (RT_FAILURE(vrc))
390 break;
391 }
392
393 if (vrc == VERR_NO_MORE_FILES)
394 vrc = VINF_SUCCESS;
395 }
396
397 RTVfsDirRelease(hVfsDir);
398 }
399
400 i_releaseUefiVariableStore();
401
402 if (RT_FAILURE(vrc))
403 return setError(VBOX_E_IPRT_ERROR, tr("Failed to query the variables: %Rrc"), vrc);
404
405 return S_OK;
406}
407
408
409HRESULT UefiVariableStore::enrollOraclePlatformKey(void)
410{
411 /* the machine needs to be mutable */
412 AutoMutableStateDependency adep(m->pMachine);
413 if (FAILED(adep.hrc())) return adep.hrc();
414
415 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
416 if (FAILED(hrc)) return hrc;
417
418 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
419
420 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
421
422 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
423 EFI_GUID GuidOwnerVBox = EFI_SIGNATURE_OWNER_GUID_VBOX;
424 RTUUID UuidVBox;
425 RTEfiGuidToUuid(&UuidVBox, &GuidOwnerVBox);
426
427 const com::Guid GuidVBox(UuidVBox);
428
429 hrc = i_uefiVarStoreAddSignatureToDb(&GuidGlobalVar, "PK", g_abUefiOracleDefPk, g_cbUefiOracleDefPk,
430 GuidVBox, SignatureType_X509);
431
432 i_releaseUefiVariableStore();
433 return hrc;
434}
435
436
437HRESULT UefiVariableStore::enrollPlatformKey(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid)
438{
439 /* the machine needs to be mutable */
440 AutoMutableStateDependency adep(m->pMachine);
441 if (FAILED(adep.hrc())) return adep.hrc();
442
443 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
444 if (FAILED(hrc)) return hrc;
445
446 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
447
448 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
449 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "PK", aData, aOwnerUuid, SignatureType_X509);
450
451 i_releaseUefiVariableStore();
452 return hrc;
453}
454
455
456HRESULT UefiVariableStore::addKek(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
457{
458 /* the machine needs to be mutable */
459 AutoMutableStateDependency adep(m->pMachine);
460 if (FAILED(adep.hrc())) return adep.hrc();
461
462 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
463 if (FAILED(hrc)) return hrc;
464
465 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
466
467 EFI_GUID GuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
468 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidGlobalVar, "KEK", aData, aOwnerUuid, enmSignatureType);
469
470 i_releaseUefiVariableStore();
471 return hrc;
472}
473
474
475HRESULT UefiVariableStore::addSignatureToDb(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
476{
477 /* the machine needs to be mutable */
478 AutoMutableStateDependency adep(m->pMachine);
479 if (FAILED(adep.hrc())) return adep.hrc();
480
481 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
482 if (FAILED(hrc)) return hrc;
483
484 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
485
486 EFI_GUID GuidSecurityDb = EFI_GLOBAL_VARIABLE_GUID;
487 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "db", aData, aOwnerUuid, enmSignatureType);
488
489 i_releaseUefiVariableStore();
490 return hrc;
491}
492
493
494HRESULT UefiVariableStore::addSignatureToDbx(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
495{
496 /* the machine needs to be mutable */
497 AutoMutableStateDependency adep(m->pMachine);
498 if (FAILED(adep.hrc())) return adep.hrc();
499
500 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
501 if (FAILED(hrc)) return hrc;
502
503 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
504
505 EFI_GUID GuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
506 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidSecurityDb, "dbx", aData, aOwnerUuid, enmSignatureType);
507
508 i_releaseUefiVariableStore();
509 return hrc;
510}
511
512
513HRESULT UefiVariableStore::enrollDefaultMsSignatures(void)
514{
515 /* the machine needs to be mutable */
516 AutoMutableStateDependency adep(m->pMachine);
517 if (FAILED(adep.hrc())) return adep.hrc();
518
519 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
520 if (FAILED(hrc)) return hrc;
521
522 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
523
524 EFI_GUID EfiGuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
525 EFI_GUID EfiGuidGlobalVar = EFI_GLOBAL_VARIABLE_GUID;
526
527 /** @todo This conversion from EFI GUID -> IPRT UUID -> Com GUID is nuts... */
528 EFI_GUID EfiGuidMs = EFI_SIGNATURE_OWNER_GUID_MICROSOFT;
529 RTUUID UuidMs;
530 RTEfiGuidToUuid(&UuidMs, &EfiGuidMs);
531
532 const com::Guid GuidMs(UuidMs);
533
534 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidGlobalVar, "KEK", g_abUefiMicrosoftKek, g_cbUefiMicrosoftKek,
535 GuidMs, SignatureType_X509);
536 if (SUCCEEDED(hrc))
537 {
538 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidGlobalVar, "KEK", g_abUefiMicrosoftKek2023, g_cbUefiMicrosoftKek2023,
539 GuidMs, SignatureType_X509);
540 if (SUCCEEDED(hrc))
541 {
542 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoft3rdCa, g_cbUefiMicrosoft3rdCa,
543 GuidMs, SignatureType_X509);
544 if (SUCCEEDED(hrc))
545 {
546 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoft3rdCa2023, g_cbUefiMicrosoft3rdCa2023,
547 GuidMs, SignatureType_X509);
548 if (SUCCEEDED(hrc))
549 {
550 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftWinCa, g_cbUefiMicrosoftWinCa,
551 GuidMs, SignatureType_X509);
552 if (SUCCEEDED(hrc))
553 hrc = i_uefiVarStoreAddSignatureToDb(&EfiGuidSecurityDb, "db", g_abUefiMicrosoftWinCa2023, g_cbUefiMicrosoftWinCa2023,
554 GuidMs, SignatureType_X509);
555 }
556 }
557 }
558 }
559
560 i_releaseUefiVariableStore();
561 return hrc;
562}
563
564
565HRESULT UefiVariableStore::addSignatureToMok(const std::vector<BYTE> &aData, const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
566{
567 /* the machine needs to be mutable */
568 AutoMutableStateDependency adep(m->pMachine);
569 if (FAILED(adep.hrc())) return adep.hrc();
570
571 HRESULT hrc = i_retainUefiVariableStore(false /*fReadonly*/);
572 if (FAILED(hrc)) return hrc;
573
574 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
575
576 EFI_GUID GuidMokList = EFI_IMAGE_MOK_DATABASE_GUID;
577 hrc = i_uefiVarStoreAddSignatureToDbVec(&GuidMokList, "MokList", aData, aOwnerUuid, enmSignatureType, false /*fRuntime*/);
578
579 i_releaseUefiVariableStore();
580 return hrc;
581}
582
583
584
585
586/**
587 * Sets the given attributes for the given EFI variable store variable.
588 *
589 * @returns IPRT status code.
590 * @param pszVar The variable to set the attributes for.
591 * @param fAttr The attributes to set, see EFI_VAR_HEADER_ATTR_XXX.
592 */
593int UefiVariableStore::i_uefiVarStoreSetVarAttr(const char *pszVar, uint32_t fAttr)
594{
595 char szVarPath[_1K];
596 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
597 Assert(cch > 0); RT_NOREF(cch);
598
599 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
600 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
601 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
602 &hVfsFileAttr);
603 if (RT_SUCCESS(vrc))
604 {
605 uint32_t fAttrLe = RT_H2LE_U32(fAttr);
606 vrc = RTVfsFileWrite(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbWritten*/);
607 RTVfsFileRelease(hVfsFileAttr);
608 }
609
610 return vrc;
611}
612
613
614/**
615 * Queries the attributes for the given EFI variable store variable.
616 *
617 * @returns IPRT status code.
618 * @param pszVar The variable to query the attributes for.
619 * @param pfAttr Where to store the attributes on success.
620 */
621int UefiVariableStore::i_uefiVarStoreQueryVarAttr(const char *pszVar, uint32_t *pfAttr)
622{
623 char szVarPath[_1K];
624 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
625 Assert(cch > 0); RT_NOREF(cch);
626
627 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
628 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
629 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
630 &hVfsFileAttr);
631 if (RT_SUCCESS(vrc))
632 {
633 uint32_t fAttrLe = 0;
634 vrc = RTVfsFileRead(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbRead*/);
635 RTVfsFileRelease(hVfsFileAttr);
636 if (RT_SUCCESS(vrc))
637 *pfAttr = RT_LE2H_U32(fAttrLe);
638 }
639
640 return vrc;
641}
642
643
644/**
645 * Queries the data size for the given variable.
646 *
647 * @returns IPRT status code.
648 * @param pszVar The variable to query the size for.
649 * @param pcbVar Where to store the size of the variable data on success.
650 */
651int UefiVariableStore::i_uefiVarStoreQueryVarSz(const char *pszVar, uint64_t *pcbVar)
652{
653 char szVarPath[_1K];
654 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
655 Assert(cch > 0); RT_NOREF(cch);
656
657 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
658 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
659 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
660 &hVfsFile);
661 if (RT_SUCCESS(vrc))
662 {
663 vrc = RTVfsFileQuerySize(hVfsFile, pcbVar);
664 RTVfsFileRelease(hVfsFile);
665 }
666 else if (vrc == VERR_PATH_NOT_FOUND)
667 vrc = VERR_FILE_NOT_FOUND;
668
669 return vrc;
670}
671
672
673/**
674 * Returns the owner UUID of the given variable.
675 *
676 * @returns IPRT status code.
677 * @param pszVar The variable to query the owner UUID for.
678 * @param pUuid Where to store the owner UUID on success.
679 */
680int UefiVariableStore::i_uefiVarStoreQueryVarOwnerUuid(const char *pszVar, PRTUUID pUuid)
681{
682 char szVarPath[_1K];
683 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/uuid", pszVar);
684 Assert(cch > 0); RT_NOREF(cch);
685
686 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
687 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
688 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
689 &hVfsFileAttr);
690 if (RT_SUCCESS(vrc))
691 {
692 EFI_GUID OwnerGuid;
693 vrc = RTVfsFileRead(hVfsFileAttr, &OwnerGuid, sizeof(OwnerGuid), NULL /*pcbRead*/);
694 RTVfsFileRelease(hVfsFileAttr);
695 if (RT_SUCCESS(vrc))
696 RTEfiGuidToUuid(pUuid, &OwnerGuid);
697 }
698
699 return vrc;
700}
701
702
703/**
704 * Converts the given vector of variables attributes to a bitmask used internally.
705 *
706 * @returns Mask of UEFI variable attributes.
707 * @param vecAttributes Vector of variable atttributes.
708 */
709uint32_t UefiVariableStore::i_uefiVarAttrToMask(const std::vector<UefiVariableAttributes_T> &vecAttributes)
710{
711 uint32_t fAttr = 0;
712
713 for (size_t i = 0; i < vecAttributes.size(); i++)
714 fAttr |= (ULONG)vecAttributes[i];
715
716 return fAttr;
717}
718
719
720/**
721 * Converts the given aatribute mask to the attribute vector used externally.
722 *
723 * @param fAttr The attribute mask.
724 * @param aAttributes The vector to store the attibutes in.
725 */
726void UefiVariableStore::i_uefiAttrMaskToVec(uint32_t fAttr, std::vector<UefiVariableAttributes_T> &aAttributes)
727{
728 if (fAttr & EFI_VAR_HEADER_ATTR_NON_VOLATILE)
729 aAttributes.push_back(UefiVariableAttributes_NonVolatile);
730 if (fAttr & EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS)
731 aAttributes.push_back(UefiVariableAttributes_BootServiceAccess);
732 if (fAttr & EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS)
733 aAttributes.push_back(UefiVariableAttributes_RuntimeAccess);
734 if (fAttr & EFI_VAR_HEADER_ATTR_HW_ERROR_RECORD)
735 aAttributes.push_back(UefiVariableAttributes_HwErrorRecord);
736 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_AUTH_WRITE_ACCESS)
737 aAttributes.push_back(UefiVariableAttributes_AuthWriteAccess);
738 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS)
739 aAttributes.push_back(UefiVariableAttributes_AuthTimeBasedWriteAccess);
740 if (fAttr & EFI_AUTH_VAR_HEADER_ATTR_APPEND_WRITE)
741 aAttributes.push_back(UefiVariableAttributes_AuthAppendWrite);
742}
743
744
745/**
746 * Retains the reference of the variable store from the parent.
747 *
748 * @returns COM status code.
749 * @param fReadonly Flag whether the access is readonly.
750 */
751HRESULT UefiVariableStore::i_retainUefiVariableStore(bool fReadonly)
752{
753 Assert(m->hVfsUefiVarStore = NIL_RTVFS);
754 return m->pParent->i_retainUefiVarStore(&m->hVfsUefiVarStore, fReadonly);
755}
756
757
758/**
759 * Releases the reference of the variable store from the parent.
760 *
761 * @returns COM status code.
762 */
763HRESULT UefiVariableStore::i_releaseUefiVariableStore(void)
764{
765 RTVFS hVfs = m->hVfsUefiVarStore;
766
767 m->hVfsUefiVarStore = NIL_RTVFS;
768 return m->pParent->i_releaseUefiVarStore(hVfs);
769}
770
771
772/**
773 * Adds the given variable to the variable store.
774 *
775 * @returns IPRT status code.
776 * @param pGuid The EFI GUID of the variable.
777 * @param pszVar The variable name.
778 * @param fAttr Attributes for the variable.
779 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
780 */
781HRESULT UefiVariableStore::i_uefiVarStoreAddVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, PRTVFSFILE phVfsFile)
782{
783 RTUUID UuidVar;
784 RTEfiGuidToUuid(&UuidVar, pGuid);
785
786 char szVarPath[_1K];
787 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-uuid/%RTuuid/%s", &UuidVar, pszVar);
788 Assert(cch > 0); RT_NOREF(cch);
789
790 HRESULT hrc = S_OK;
791 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
792 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
793 phVfsFile);
794 if ( vrc == VERR_PATH_NOT_FOUND
795 || vrc == VERR_FILE_NOT_FOUND)
796 {
797 /*
798 * Try to create the owner GUID of the variable by creating the appropriate directory,
799 * ignore error if it exists already.
800 */
801 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
802 vrc = RTVfsOpenRoot(m->hVfsUefiVarStore, &hVfsDirRoot);
803 if (RT_SUCCESS(vrc))
804 {
805 char szGuidPath[_1K];
806 cch = RTStrPrintf2(szGuidPath, sizeof(szGuidPath), "by-uuid/%RTuuid", &UuidVar);
807 Assert(cch > 0);
808
809 RTVFSDIR hVfsDirGuid = NIL_RTVFSDIR;
810 vrc = RTVfsDirCreateDir(hVfsDirRoot, szGuidPath, 0755, 0 /*fFlags*/, &hVfsDirGuid);
811 if (RT_SUCCESS(vrc))
812 RTVfsDirRelease(hVfsDirGuid);
813 else if (vrc == VERR_ALREADY_EXISTS)
814 vrc = VINF_SUCCESS;
815
816 RTVfsDirRelease(hVfsDirRoot);
817 }
818 else
819 hrc = setError(E_FAIL, tr("Opening variable storage root directory failed: %Rrc"), vrc);
820
821 if (RT_SUCCESS(vrc))
822 {
823 vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
824 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE,
825 phVfsFile);
826 if (RT_SUCCESS(vrc))
827 vrc = i_uefiVarStoreSetVarAttr(pszVar, fAttr);
828 }
829
830 if (RT_FAILURE(vrc))
831 hrc = setError(E_FAIL, tr("Creating the variable '%s' failed: %Rrc"), pszVar, vrc);
832 }
833
834 return hrc;
835}
836
837
838/**
839 * Tries to open the given variable from the variable store and returns a file handle.
840 *
841 * @returns IPRT status code.
842 * @param pszVar The variable name.
843 * @param phVfsFile Where to return the VFS file handle to the created variable on success.
844 */
845HRESULT UefiVariableStore::i_uefiVarStoreOpenVar(const char *pszVar, PRTVFSFILE phVfsFile)
846{
847 char szVarPath[_1K];
848 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
849 Assert(cch > 0); RT_NOREF(cch);
850
851 HRESULT hrc = S_OK;
852 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
853 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
854 phVfsFile);
855 if ( vrc == VERR_PATH_NOT_FOUND
856 || vrc == VERR_FILE_NOT_FOUND)
857 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The variable '%s' could not be found"), pszVar);
858 else if (RT_FAILURE(vrc))
859 hrc = setError(VBOX_E_IPRT_ERROR, tr("Couldn't open variable '%s' (%Rrc)"), pszVar, vrc);
860
861 return hrc;
862}
863
864
865HRESULT UefiVariableStore::i_uefiVarStoreSetVar(PCEFI_GUID pGuid, const char *pszVar, uint32_t fAttr, const void *pvData, size_t cbData)
866{
867 RTVFSFILE hVfsFileVar = NIL_RTVFSFILE;
868
869 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszVar, fAttr, &hVfsFileVar);
870 if (SUCCEEDED(hrc))
871 {
872 int vrc = RTVfsFileWrite(hVfsFileVar, pvData, cbData, NULL /*pcbWritten*/);
873 if (RT_FAILURE(vrc))
874 hrc = setError(E_FAIL, tr("Setting the variable '%s' failed: %Rrc"), pszVar, vrc);
875
876 RTVfsFileRelease(hVfsFileVar);
877 }
878
879 return hrc;
880}
881
882
883HRESULT UefiVariableStore::i_uefiVarStoreQueryVar(const char *pszVar, void *pvData, size_t cbData)
884{
885 HRESULT hrc = S_OK;
886
887 char szVarPath[_1K];
888 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/by-name/%s", pszVar);
889 Assert(cch > 0); RT_NOREF(cch);
890
891 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
892 int vrc = RTVfsFileOpen(m->hVfsUefiVarStore, szVarPath,
893 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
894 &hVfsFile);
895 if (RT_SUCCESS(vrc))
896 {
897 vrc = RTVfsFileRead(hVfsFile, pvData, cbData, NULL /*pcbRead*/);
898 if (RT_FAILURE(vrc))
899 hrc = setError(E_FAIL, tr("Failed to read data of variable '%s': %Rrc"), pszVar, vrc);
900
901 RTVfsFileRelease(hVfsFile);
902 }
903 else
904 hrc = setError(E_FAIL, tr("Failed to open variable '%s' for reading: %Rrc"), pszVar, vrc);
905
906 return hrc;
907}
908
909HRESULT UefiVariableStore::i_uefiSigDbAddSig(RTEFISIGDB hEfiSigDb, const void *pvData, size_t cbData,
910 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType)
911{
912 RTEFISIGTYPE enmSigType = RTEFISIGTYPE_INVALID;
913
914 switch (enmSignatureType)
915 {
916 case SignatureType_X509:
917 enmSigType = RTEFISIGTYPE_X509;
918 break;
919 case SignatureType_Sha256:
920 enmSigType = RTEFISIGTYPE_SHA256;
921 break;
922 default:
923 return setError(E_FAIL, tr("The given signature type is not supported"));
924 }
925
926 int vrc = RTEfiSigDbAddSignatureFromBuf(hEfiSigDb, enmSigType, aOwnerUuid.raw(), pvData, cbData);
927 if (RT_SUCCESS(vrc))
928 return S_OK;
929
930 return setError(E_FAIL, tr("Failed to add signature to the database (%Rrc)"), vrc);
931}
932
933
934HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDb(PCEFI_GUID pGuid, const char *pszDb, const void *pvData, size_t cbData,
935 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType, bool fRuntime)
936{
937 RTVFSFILE hVfsFileSigDb = NIL_RTVFSFILE;
938
939 HRESULT hrc = i_uefiVarStoreAddVar(pGuid, pszDb,
940 EFI_VAR_HEADER_ATTR_NON_VOLATILE
941 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
942 | (fRuntime ? EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS : 0)
943 | EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS,
944 &hVfsFileSigDb);
945 if (SUCCEEDED(hrc))
946 {
947 RTEFISIGDB hEfiSigDb;
948
949 int vrc = RTEfiSigDbCreate(&hEfiSigDb);
950 if (RT_SUCCESS(vrc))
951 {
952 vrc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFileSigDb);
953 if (RT_SUCCESS(vrc))
954 {
955 hrc = i_uefiSigDbAddSig(hEfiSigDb, pvData, cbData, aOwnerUuid, enmSignatureType);
956 if (SUCCEEDED(hrc))
957 {
958 vrc = RTVfsFileSeek(hVfsFileSigDb, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
959 AssertRC(vrc);
960
961 vrc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFileSigDb);
962 if (RT_FAILURE(vrc))
963 hrc = setError(E_FAIL, tr("Writing updated signature database failed: %Rrc"), vrc);
964 }
965 }
966 else
967 hrc = setError(E_FAIL, tr("Loading signature database failed: %Rrc"), vrc);
968
969 RTEfiSigDbDestroy(hEfiSigDb);
970 }
971 else
972 hrc = setError(E_FAIL, tr("Creating signature database failed: %Rrc"), vrc);
973
974 RTVfsFileRelease(hVfsFileSigDb);
975 }
976
977 return hrc;
978}
979
980
981HRESULT UefiVariableStore::i_uefiVarStoreAddSignatureToDbVec(PCEFI_GUID pGuid, const char *pszDb, const std::vector<BYTE> &aData,
982 const com::Guid &aOwnerUuid, SignatureType_T enmSignatureType, bool fRuntime)
983{
984 return i_uefiVarStoreAddSignatureToDb(pGuid, pszDb, &aData.front(), aData.size(), aOwnerUuid, enmSignatureType, fRuntime);
985}
986
987/* 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