VirtualBox

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

Last change on this file since 105305 was 104794, checked in by vboxsync, 7 months ago

Main: Actually add new Microsoft KEK cert issued 2023, was forgotten in previous change. bugref:10699

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