VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/NvramStoreImpl.cpp

Last change on this file was 103532, checked in by vboxsync, 3 months ago

VBoxManage: Add subcommand for enabling UEFI secure boot (and show the status in the VM infos).
Main/NVRAMStore+UefiVariableStore: Tweaks to allow reading the UEFI secure boot state when the VM isn't mutable.
doc/manual: Update VBoxManage manpage.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.5 KB
RevLine 
[91326]1/* $Id: NvramStoreImpl.cpp 103532 2024-02-22 14:05:31Z vboxsync $ */
2/** @file
3 * VirtualBox COM NVRAM store class implementation
4 */
5
6/*
[98103]7 * Copyright (C) 2021-2023 Oracle and/or its affiliates.
[91326]8 *
[96407]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
[91326]26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_NVRAMSTORE
29#include "LoggingNew.h"
30
31#include "NvramStoreImpl.h"
32#ifdef VBOX_COM_INPROC
33# include "ConsoleImpl.h"
34#else
35# include "MachineImpl.h"
[91614]36# include "GuestOSTypeImpl.h"
[91396]37# include "AutoStateDep.h"
[91326]38#endif
[91396]39#include "UefiVariableStoreImpl.h"
[94743]40#include "VirtualBoxImpl.h"
[91326]41
42#include "AutoCaller.h"
43
44#include <VBox/com/array.h>
45#include <VBox/vmm/pdmdrv.h>
46#include <VBox/err.h>
47
48#include <iprt/cpp/utils.h>
49#include <iprt/efi.h>
50#include <iprt/file.h>
51#include <iprt/vfs.h>
52#include <iprt/zip.h>
53
54
55// defines
56////////////////////////////////////////////////////////////////////////////////
57
[94514]58/** Version of the NVRAM saved state unit. */
59#define NVRAM_STORE_SAVED_STATE_VERSION 1
60
61
[91326]62// globals
63////////////////////////////////////////////////////////////////////////////////
64
65/**
66 * NVRAM store driver instance data.
67 */
68typedef struct DRVMAINNVRAMSTORE
69{
70 /** Pointer to the keyboard object. */
71 NvramStore *pNvramStore;
72 /** Pointer to the driver instance structure. */
73 PPDMDRVINS pDrvIns;
74 /** Our VFS connector interface. */
75 PDMIVFSCONNECTOR IVfs;
76} DRVMAINNVRAMSTORE, *PDRVMAINNVRAMSTORE;
77
78/** The NVRAM store map keyed by namespace/entity. */
79typedef std::map<Utf8Str, RTVFSFILE> NvramStoreMap;
80/** The NVRAM store map iterator. */
81typedef std::map<Utf8Str, RTVFSFILE>::iterator NvramStoreIter;
82
83struct BackupableNvramStoreData
84{
85 BackupableNvramStoreData()
86 { }
87
88 /** The NVRAM file path. */
89 com::Utf8Str strNvramPath;
[94660]90#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
91 /** The key id used for encrypting the NVRAM file */
92 com::Utf8Str strKeyId;
93 /** The key store containing the encrypting DEK */
94 com::Utf8Str strKeyStore;
95#endif
[91326]96 /** The NVRAM store. */
97 NvramStoreMap mapNvram;
98};
99
100/////////////////////////////////////////////////////////////////////////////
101// NvramStore::Data structure
102/////////////////////////////////////////////////////////////////////////////
103
104struct NvramStore::Data
105{
106 Data()
107 : pParent(NULL)
108#ifdef VBOX_COM_INPROC
109 , cRefs(0)
[96853]110 , fSsmSaved(false)
[91326]111#endif
[94743]112#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
113 , mpKeyStore(NULL)
114#endif
[91326]115 { }
116
117#ifdef VBOX_COM_INPROC
118 /** The Console owning this NVRAM store. */
119 Console * const pParent;
120 /** Number of references held to this NVRAM store from the various devices/drivers. */
121 volatile uint32_t cRefs;
[94514]122 /** Flag whether the NVRAM data was saved during a save state operation
123 * preventing it from getting written to the backing file. */
124 bool fSsmSaved;
[91326]125#else
126 /** The Machine object owning this NVRAM store. */
[91396]127 Machine * const pParent;
[91326]128 /** The peer NVRAM store object. */
[91396]129 ComObjPtr<NvramStore> pPeer;
130 /** The UEFI variable store. */
131 const ComObjPtr<UefiVariableStore> pUefiVarStore;
[91326]132#endif
133
[94743]134#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
135 /* Store for secret keys. */
136 SecretKeyStore *mpKeyStore;
137#endif
138
[91326]139 Backupable<BackupableNvramStoreData> bd;
140};
141
142// constructor / destructor
143////////////////////////////////////////////////////////////////////////////////
144
145DEFINE_EMPTY_CTOR_DTOR(NvramStore)
146
147HRESULT NvramStore::FinalConstruct()
148{
149 return BaseFinalConstruct();
150}
151
152void NvramStore::FinalRelease()
153{
154 uninit();
155 BaseFinalRelease();
156}
157
158// public initializer/uninitializer for internal purposes only
159/////////////////////////////////////////////////////////////////////////////
160
[94743]161/**
162 * Initialization stuff shared across the different methods.
163 *
164 * @returns COM result indicator
165 */
166int NvramStore::initImpl()
167{
168 m = new Data();
169
170#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
171# ifdef VBOX_COM_INPROC
172 bool fNonPageable = true;
173# else
174 /* Non-pageable memory is not accessible for non-VM process */
175 bool fNonPageable = false;
176# endif
177
178 m->mpKeyStore = new SecretKeyStore(fNonPageable /* fKeyBufNonPageable */);
179 AssertReturn(m->mpKeyStore, VERR_NO_MEMORY);
180#endif
181
182 return VINF_SUCCESS;
183}
184
185
[91326]186#if !defined(VBOX_COM_INPROC)
187/**
188 * Initializes the NVRAM store object.
189 *
190 * @returns COM result indicator
191 */
192HRESULT NvramStore::init(Machine *aParent)
193{
194 LogFlowThisFuncEnter();
195 LogFlowThisFunc(("aParent: %p\n", aParent));
196
197 ComAssertRet(aParent, E_INVALIDARG);
198
199 /* Enclose the state transition NotReady->InInit->Ready */
200 AutoInitSpan autoInitSpan(this);
201 AssertReturn(autoInitSpan.isOk(), E_FAIL);
202
[94743]203 int vrc = initImpl();
204 if (RT_FAILURE(vrc))
205 return E_FAIL;
[91326]206
207 /* share the parent weakly */
208 unconst(m->pParent) = aParent;
209
210 m->bd.allocate();
211
212 autoInitSpan.setSucceeded();
213
214 LogFlowThisFuncLeave();
215 return S_OK;
216}
217
218/**
219 * Initializes the NVRAM store object given another NVRAM store object
220 * (a kind of copy constructor). This object shares data with
221 * the object passed as an argument.
222 *
223 * @note This object must be destroyed before the original object
224 * it shares data with is destroyed.
225 */
226HRESULT NvramStore::init(Machine *aParent, NvramStore *that)
227{
228 LogFlowThisFuncEnter();
229 LogFlowThisFunc(("aParent: %p, that: %p\n", aParent, that));
230
231 ComAssertRet(aParent && that, E_INVALIDARG);
232
233 /* Enclose the state transition NotReady->InInit->Ready */
234 AutoInitSpan autoInitSpan(this);
235 AssertReturn(autoInitSpan.isOk(), E_FAIL);
236
[94743]237 initImpl();
[91326]238
239 unconst(m->pParent) = aParent;
240 m->pPeer = that;
241
242 AutoWriteLock thatlock(that COMMA_LOCKVAL_SRC_POS);
243 m->bd.share(that->m->bd);
244
245 autoInitSpan.setSucceeded();
246
247 LogFlowThisFuncLeave();
248 return S_OK;
249}
250
251/**
252 * Initializes the guest object given another guest object
253 * (a kind of copy constructor). This object makes a private copy of data
254 * of the original object passed as an argument.
255 */
256HRESULT NvramStore::initCopy(Machine *aParent, NvramStore *that)
257{
258 LogFlowThisFuncEnter();
259 LogFlowThisFunc(("aParent: %p, that: %p\n", aParent, that));
260
261 ComAssertRet(aParent && that, E_INVALIDARG);
262
263 /* Enclose the state transition NotReady->InInit->Ready */
264 AutoInitSpan autoInitSpan(this);
265 AssertReturn(autoInitSpan.isOk(), E_FAIL);
266
[94743]267 initImpl();
[91326]268
269 unconst(m->pParent) = aParent;
270 // mPeer is left null
271
272 AutoWriteLock thatlock(that COMMA_LOCKVAL_SRC_POS);
273 m->bd.attachCopy(that->m->bd);
274
275 autoInitSpan.setSucceeded();
276
277 LogFlowThisFuncLeave();
278 return S_OK;
279}
280
281#else
282
283/**
284 * Initializes the NVRAM store object.
285 *
286 * @returns COM result indicator
287 * @param aParent Handle of our parent object
288 * @param strNonVolatileStorageFile The NVRAM file path.
289 */
290HRESULT NvramStore::init(Console *aParent, const com::Utf8Str &strNonVolatileStorageFile)
291{
292 LogFlowThisFunc(("aParent=%p\n", aParent));
293
294 ComAssertRet(aParent, E_INVALIDARG);
295
296 /* Enclose the state transition NotReady->InInit->Ready */
297 AutoInitSpan autoInitSpan(this);
298 AssertReturn(autoInitSpan.isOk(), E_FAIL);
299
[94743]300 initImpl();
301
[91326]302 unconst(m->pParent) = aParent;
303
304 m->bd.allocate();
305 m->bd->strNvramPath = strNonVolatileStorageFile;
306
307 /* Confirm a successful initialization */
308 autoInitSpan.setSucceeded();
309
310 return S_OK;
311}
312#endif /* VBOX_COM_INPROC */
313
314
315/**
316 * Uninitializes the instance and sets the ready flag to FALSE.
317 * Called either from FinalRelease() or by the parent when it gets destroyed.
318 */
319void NvramStore::uninit()
320{
321 LogFlowThisFuncEnter();
322
323 /* Enclose the state transition Ready->InUninit->NotReady */
324 AutoUninitSpan autoUninitSpan(this);
325 if (autoUninitSpan.uninitDone())
326 return;
327
328 unconst(m->pParent) = NULL;
[91434]329#ifndef VBOX_COM_INPROC
330 unconst(m->pUefiVarStore) = NULL;
331#endif
[91326]332
333 /* Delete the NVRAM content. */
334 NvramStoreIter it = m->bd->mapNvram.begin();
335 while (it != m->bd->mapNvram.end())
336 {
337 RTVfsFileRelease(it->second);
338 it++;
339 }
340
341 m->bd->mapNvram.clear();
[94819]342 m->bd.free();
[91326]343
[94743]344#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
345 if (m->mpKeyStore != NULL)
346 delete m->mpKeyStore;
347#endif
348
[91326]349 delete m;
350 m = NULL;
351
352 LogFlowThisFuncLeave();
353}
354
355
356HRESULT NvramStore::getNonVolatileStorageFile(com::Utf8Str &aNonVolatileStorageFile)
357{
358#ifndef VBOX_COM_INPROC
359 Utf8Str strTmp;
360 {
361 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
362 strTmp = m->bd->strNvramPath;
363 }
364
365 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
366 if (strTmp.isEmpty())
367 strTmp = m->pParent->i_getDefaultNVRAMFilename();
368 if (strTmp.isNotEmpty())
369 m->pParent->i_calculateFullPath(strTmp, aNonVolatileStorageFile);
370#else
371 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
372 aNonVolatileStorageFile = m->bd->strNvramPath;
373#endif
374
375 return S_OK;
376}
377
378
[91396]379HRESULT NvramStore::getUefiVariableStore(ComPtr<IUefiVariableStore> &aUefiVarStore)
380{
381#ifndef VBOX_COM_INPROC
[91434]382 Utf8Str strPath;
383 NvramStore::getNonVolatileStorageFile(strPath);
384
[91396]385 /* We need a write lock because of the lazy initialization. */
386 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
387
[91434]388 /* Check if we have to create the UEFI variable store object */
[91396]389 HRESULT hrc = S_OK;
390 if (!m->pUefiVarStore)
391 {
392 /* Load the NVRAM file first if it isn't already. */
393 if (!m->bd->mapNvram.size())
394 {
[91434]395 int vrc = i_loadStore(strPath.c_str());
[91396]396 if (RT_FAILURE(vrc))
397 hrc = setError(E_FAIL, tr("Loading the NVRAM store failed (%Rrc)\n"), vrc);
398 }
399
400 if (SUCCEEDED(hrc))
401 {
402 NvramStoreIter it = m->bd->mapNvram.find("efi/nvram");
403 if (it != m->bd->mapNvram.end())
404 {
[91535]405 unconst(m->pUefiVarStore).createObject();
406 m->pUefiVarStore->init(this, m->pParent);
[91396]407 }
408 else
409 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The UEFI NVRAM file is not existing for this machine."));
410 }
411 }
412
413 if (SUCCEEDED(hrc))
[91434]414 {
[91396]415 m->pUefiVarStore.queryInterfaceTo(aUefiVarStore.asOutParam());
[103532]416 /* The "modified" state is handled by i_retainUefiVarStore. */
[91434]417 }
418
[91396]419 return hrc;
420#else
421 NOREF(aUefiVarStore);
422 return E_NOTIMPL;
423#endif
424}
425
426
[94660]427HRESULT NvramStore::getKeyId(com::Utf8Str &aKeyId)
428{
429 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
430
431#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
432 aKeyId = m->bd->strKeyId;
433#else
434 aKeyId = com::Utf8Str::Empty;
435#endif
436
437 return S_OK;
438}
439
440
441HRESULT NvramStore::getKeyStore(com::Utf8Str &aKeyStore)
442{
443 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
444
445#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
446 aKeyStore = m->bd->strKeyStore;
447#else
448 aKeyStore = com::Utf8Str::Empty;
449#endif
450
451 return S_OK;
452}
453
454
[91396]455HRESULT NvramStore::initUefiVariableStore(ULONG aSize)
456{
[91434]457#ifndef VBOX_COM_INPROC
458 if (aSize != 0)
459 return setError(E_NOTIMPL, tr("Supporting another NVRAM size apart from the default one is not supported right now"));
460
461 /* the machine needs to be mutable */
462 AutoMutableStateDependency adep(m->pParent);
[98262]463 if (FAILED(adep.hrc())) return adep.hrc();
[91434]464
465 Utf8Str strPath;
466 NvramStore::getNonVolatileStorageFile(strPath);
467
468 /* We need a write lock because of the lazy initialization. */
[91457]469 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
[91434]470 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
471
[91457]472 if (m->pParent->i_getFirmwareType() == FirmwareType_BIOS)
473 return setError(VBOX_E_NOT_SUPPORTED, tr("The selected firmware type doesn't support a UEFI variable store"));
474
[91434]475 /* Load the NVRAM file first if it isn't already. */
476 HRESULT hrc = S_OK;
477 if (!m->bd->mapNvram.size())
478 {
479 int vrc = i_loadStore(strPath.c_str());
480 if (RT_FAILURE(vrc))
481 hrc = setError(E_FAIL, tr("Loading the NVRAM store failed (%Rrc)\n"), vrc);
482 }
483
484 if (SUCCEEDED(hrc))
485 {
486 int vrc = VINF_SUCCESS;
487 RTVFSFILE hVfsUefiVarStore = NIL_RTVFSFILE;
488 NvramStoreIter it = m->bd->mapNvram.find("efi/nvram");
489 if (it != m->bd->mapNvram.end())
490 hVfsUefiVarStore = it->second;
491 else
492 {
493 /* Create a new file. */
494 vrc = RTVfsMemFileCreate(NIL_RTVFSIOSTREAM, 0 /*cbEstimate*/, &hVfsUefiVarStore);
495 if (RT_SUCCESS(vrc))
496 {
497 /** @todo The size is hardcoded to match what the firmware image uses right now which is a gross hack... */
[91497]498 vrc = RTVfsFileSetSize(hVfsUefiVarStore, 540672, RTVFSFILE_SIZE_F_NORMAL);
[91434]499 if (RT_SUCCESS(vrc))
500 m->bd->mapNvram["efi/nvram"] = hVfsUefiVarStore;
501 else
502 RTVfsFileRelease(hVfsUefiVarStore);
503 }
504 }
505
506 if (RT_SUCCESS(vrc))
507 {
508 vrc = RTEfiVarStoreCreate(hVfsUefiVarStore, 0 /*offStore*/, 0 /*cbStore*/, RTEFIVARSTORE_CREATE_F_DEFAULT, 0 /*cbBlock*/,
509 NULL /*pErrInfo*/);
510 if (RT_FAILURE(vrc))
511 return setError(E_FAIL, tr("Failed to initialize the UEFI variable store (%Rrc)"), vrc);
512 }
513 else
514 return setError(E_FAIL, tr("Failed to initialize the UEFI variable store (%Rrc)"), vrc);
515
516 m->pParent->i_setModified(Machine::IsModified_NvramStore);
517 }
518
519 return hrc;
520#else
[91396]521 NOREF(aSize);
522 return E_NOTIMPL;
[91434]523#endif
[91396]524}
525
526
[91326]527Utf8Str NvramStore::i_getNonVolatileStorageFile()
528{
529 AutoCaller autoCaller(this);
[94912]530 AssertReturn(autoCaller.isOk(), Utf8Str::Empty);
[91326]531
532 Utf8Str strTmp;
533 NvramStore::getNonVolatileStorageFile(strTmp);
534 return strTmp;
535}
536
537
538/**
539 * Loads the NVRAM store from the given TAR filesystem stream.
540 *
541 * @returns IPRT status code.
542 * @param hVfsFssTar Handle to the tar filesystem stream.
543 */
544int NvramStore::i_loadStoreFromTar(RTVFSFSSTREAM hVfsFssTar)
545{
[94912]546 int vrc = VINF_SUCCESS;
[91326]547
548 /*
549 * Process the stream.
550 */
551 for (;;)
552 {
553 /*
554 * Retrieve the next object.
555 */
556 char *pszName;
557 RTVFSOBJ hVfsObj;
[94912]558 vrc = RTVfsFsStrmNext(hVfsFssTar, &pszName, NULL, &hVfsObj);
559 if (RT_FAILURE(vrc))
[91326]560 {
[94912]561 if (vrc == VERR_EOF)
562 vrc = VINF_SUCCESS;
[91326]563 break;
564 }
565
566 RTFSOBJINFO UnixInfo;
[94912]567 vrc = RTVfsObjQueryInfo(hVfsObj, &UnixInfo, RTFSOBJATTRADD_UNIX);
568 if (RT_SUCCESS(vrc))
[91326]569 {
570 switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
571 {
572 case RTFS_TYPE_FILE:
573 {
574 LogRel(("NvramStore: Loading '%s' from archive\n", pszName));
575 RTVFSIOSTREAM hVfsIosEntry = RTVfsObjToIoStream(hVfsObj);
576 Assert(hVfsIosEntry != NIL_RTVFSIOSTREAM);
577
578 RTVFSFILE hVfsFileEntry;
[94912]579 vrc = RTVfsMemorizeIoStreamAsFile(hVfsIosEntry, RTFILE_O_READ | RTFILE_O_WRITE, &hVfsFileEntry);
580 if (RT_FAILURE(vrc))
[91326]581 break;
582 RTVfsIoStrmRelease(hVfsIosEntry);
583
584 m->bd->mapNvram[Utf8Str(pszName)] = hVfsFileEntry;
585 break;
586 }
587 case RTFS_TYPE_DIRECTORY:
588 break;
589 default:
[94912]590 vrc = VERR_NOT_SUPPORTED;
[91326]591 break;
592 }
593 }
594
595 /*
596 * Release the current object and string.
597 */
598 RTVfsObjRelease(hVfsObj);
599 RTStrFree(pszName);
600
[94912]601 if (RT_FAILURE(vrc))
[91326]602 break;
603 }
604
[94912]605 return vrc;
[91326]606}
607
[99739]608#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
[91326]609
610/**
[94743]611 * Sets up the encryption or decryption machinery.
612 *
613 * @returns VBox status code.
614 * @param hVfsIosInOut Handle to the input stream to be decrypted or the destination to the encrypted
615 * output is written to.
616 * @param fEncrypt Flag whether to setup encryption or decryption.
617 * @param ppCryptoIf Where to store the pointer to the cryptographic interface which needs to be released
618 * when done.
619 * @param ppKey Where to store the pointer to the secret key buffer which needs to be released when done.
620 * @param phVfsIos Where to store the handle to the plaintext I/O stream (either input or output) on success.
621 */
622int NvramStore::i_setupEncryptionOrDecryption(RTVFSIOSTREAM hVfsIosInOut, bool fEncrypt,
623 PCVBOXCRYPTOIF *ppCryptoIf, SecretKey **ppKey,
624 PRTVFSIOSTREAM phVfsIos)
625{
[94912]626 int vrc = VINF_SUCCESS;
[94743]627 PCVBOXCRYPTOIF pCryptoIf = NULL;
628 SecretKey *pKey = NULL;
629 const char *pszPassword = NULL;
630
[94912]631 vrc = i_retainCryptoIf(&pCryptoIf);
632 if (RT_SUCCESS(vrc))
[94743]633 {
[94912]634 vrc = m->mpKeyStore->retainSecretKey(m->bd->strKeyId, &pKey);
635 if (RT_SUCCESS(vrc))
[94743]636 {
637 pszPassword = (const char *)pKey->getKeyBuffer();
638 if (fEncrypt)
[94912]639 vrc = pCryptoIf->pfnCryptoIoStrmFromVfsIoStrmEncrypt(hVfsIosInOut, m->bd->strKeyStore.c_str(), pszPassword,
640 phVfsIos);
[94743]641 else
[94912]642 vrc = pCryptoIf->pfnCryptoIoStrmFromVfsIoStrmDecrypt(hVfsIosInOut, m->bd->strKeyStore.c_str(), pszPassword,
643 phVfsIos);
644 if (RT_SUCCESS(vrc))
[94743]645 {
646 *ppCryptoIf = pCryptoIf;
647 *ppKey = pKey;
648 return VINF_SUCCESS;
649 }
650 else
651 LogRelMax(10, ("Failed to decrypt the NVRAM store using secret key ID '%s' with %Rrc\n",
[94912]652 m->bd->strKeyId.c_str(), vrc));
[94743]653
654 m->mpKeyStore->releaseSecretKey(m->bd->strKeyId);
655 }
656 else
657 LogRelMax(10, ("Failed to retain the secret key ID '%s' with %Rrc\n",
[94912]658 m->bd->strKeyId.c_str(), vrc));
[94743]659
660 i_releaseCryptoIf(pCryptoIf);
661 }
662 else
[94912]663 LogRelMax(10, ("Failed to retain the cryptographic interface with %Rrc\n", vrc));
[94743]664
[94912]665 return vrc;
[94743]666}
667
668/**
669 * Releases all resources acquired in NvramStore::i_setupEncryptionOrDecryption().
670 *
671 * @param hVfsIos Handle to the I/O stream previously created.
672 * @param pCryptoIf Pointer to the cryptographic interface being released.
673 * @param pKey Pointer to the key buffer being released.
674 */
675void NvramStore::i_releaseEncryptionOrDecryptionResources(RTVFSIOSTREAM hVfsIos, PCVBOXCRYPTOIF pCryptoIf,
676 SecretKey *pKey)
677{
678 Assert(hVfsIos != NIL_RTVFSIOSTREAM);
679 AssertPtr(pCryptoIf);
680 AssertPtr(pKey);
681
682 i_releaseCryptoIf(pCryptoIf);
[94810]683 pKey->release();
[94743]684 RTVfsIoStrmRelease(hVfsIos);
685}
686
[99739]687#endif /* VBOX_WITH_FULL_VM_ENCRYPTION */
[94743]688
689/**
[91326]690 * Loads the NVRAM store.
691 *
692 * @returns IPRT status code.
693 */
[91434]694int NvramStore::i_loadStore(const char *pszPath)
[91326]695{
696 uint64_t cbStore = 0;
[94912]697 int vrc = RTFileQuerySizeByPath(pszPath, &cbStore);
698 if (RT_SUCCESS(vrc))
[91326]699 {
700 if (cbStore <= _1M) /* Arbitrary limit to fend off bogus files because the file will be read into memory completely. */
701 {
702 /*
703 * Old NVRAM files just consist of the EFI variable store whereas starting
704 * with VirtualBox 7.0 and the introduction of the TPM the need to handle multiple
705 * independent NVRAM files came up. For those scenarios all NVRAM states are collected
706 * in a tar archive.
707 *
708 * Here we detect whether the file is the new tar archive format or whether it is just
709 * the plain EFI variable store file.
710 */
711 RTVFSIOSTREAM hVfsIosNvram;
[94912]712 vrc = RTVfsIoStrmOpenNormal(pszPath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE,
713 &hVfsIosNvram);
714 if (RT_SUCCESS(vrc))
[91326]715 {
[94743]716 RTVFSIOSTREAM hVfsIosDecrypted = NIL_RTVFSIOSTREAM;
717
718#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
719 PCVBOXCRYPTOIF pCryptoIf = NULL;
720 SecretKey *pKey = NULL;
721
722 if ( m->bd->strKeyId.isNotEmpty()
723 && m->bd->strKeyStore.isNotEmpty())
[94912]724 vrc = i_setupEncryptionOrDecryption(hVfsIosNvram, false /*fEncrypt*/,
725 &pCryptoIf, &pKey, &hVfsIosDecrypted);
[94743]726#endif
[94912]727 if (RT_SUCCESS(vrc))
[91326]728 {
[94743]729 /* Read the content. */
730 RTVFSFILE hVfsFileNvram;
[94912]731 vrc = RTVfsMemorizeIoStreamAsFile( hVfsIosDecrypted != NIL_RTVFSIOSTREAM
732 ? hVfsIosDecrypted
733 : hVfsIosNvram,
734 RTFILE_O_READ, &hVfsFileNvram);
735 if (RT_SUCCESS(vrc))
[91326]736 {
[94912]737 if (RT_SUCCESS(vrc))
[94743]738 {
739 /* Try to parse it as an EFI variable store. */
[99424]740 RTERRINFOSTATIC ErrInfo;
[94743]741 RTVFS hVfsEfiVarStore;
[99424]742 vrc = RTEfiVarStoreOpenAsVfs(hVfsFileNvram, RTVFSMNT_F_READ_ONLY, 0 /*fVarStoreFlags*/,
743 &hVfsEfiVarStore, RTErrInfoInitStatic(&ErrInfo));
[94912]744 if (RT_SUCCESS(vrc))
[94743]745 {
[94912]746 vrc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
747 AssertRC(vrc);
[91326]748
[94743]749 RTVfsFileRetain(hVfsFileNvram); /* Retain a new reference for the map. */
750 m->bd->mapNvram[Utf8Str("efi/nvram")] = hVfsFileNvram;
[91326]751
[94743]752 RTVfsRelease(hVfsEfiVarStore);
753 }
[94912]754 else if (vrc == VERR_VFS_UNKNOWN_FORMAT)
[94743]755 {
756 /* Check for the new style tar archive. */
[94912]757 vrc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
758 AssertRC(vrc);
[91326]759
[94743]760 RTVFSIOSTREAM hVfsIosTar = RTVfsFileToIoStream(hVfsFileNvram);
761 Assert(hVfsIosTar != NIL_RTVFSIOSTREAM);
[91326]762
[94743]763 RTVFSFSSTREAM hVfsFssTar;
[94912]764 vrc = RTZipTarFsStreamFromIoStream(hVfsIosTar, 0 /*fFlags*/, &hVfsFssTar);
[94743]765 RTVfsIoStrmRelease(hVfsIosTar);
[94912]766 if (RT_SUCCESS(vrc))
[94743]767 {
[94912]768 vrc = i_loadStoreFromTar(hVfsFssTar);
[94743]769 RTVfsFsStrmRelease(hVfsFssTar);
770 }
771 else
[94912]772 LogRel(("The given NVRAM file is neither a raw UEFI variable store nor a tar archive (opening failed with %Rrc)\n", vrc));
[94743]773 }
774 else
[99424]775 LogRel(("Opening the UEFI variable store '%s' failed with %Rrc%RTeim\n", pszPath, vrc, &ErrInfo.Core));
[94743]776
777 RTVfsFileRelease(hVfsFileNvram);
[91326]778 }
779 else
[94912]780 LogRel(("Failed to memorize NVRAM store '%s' with %Rrc\n", pszPath, vrc));
[91326]781 }
782 }
783
[94743]784#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
785 if (hVfsIosDecrypted != NIL_RTVFSIOSTREAM)
786 i_releaseEncryptionOrDecryptionResources(hVfsIosDecrypted, pCryptoIf, pKey);
787#endif
788
[91326]789 RTVfsIoStrmRelease(hVfsIosNvram);
790 }
791 else
[94912]792 LogRelMax(10, ("NVRAM store '%s' couldn't be opened with %Rrc\n", pszPath, vrc));
[91326]793 }
794 else
[99424]795 {
[91326]796 LogRelMax(10, ("NVRAM store '%s' exceeds limit of %u bytes, actual size is %u\n",
[91434]797 pszPath, _1M, cbStore));
[99424]798 vrc = VERR_OUT_OF_RANGE;
799 }
[91326]800 }
[94912]801 else if (vrc == VERR_FILE_NOT_FOUND) /* Valid for the first run where no NVRAM file is there. */
802 vrc = VINF_SUCCESS;
[91326]803
[94912]804 return vrc;
[91326]805}
806
807
808/**
809 * Saves the NVRAM store as a tar archive.
810 */
[91536]811int NvramStore::i_saveStoreAsTar(const char *pszPath)
[91326]812{
813 uint32_t offError = 0;
814 RTERRINFOSTATIC ErrInfo;
815 RTVFSIOSTREAM hVfsIos;
816
[94912]817 int vrc = RTVfsChainOpenIoStream(pszPath, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
818 &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
819 if (RT_SUCCESS(vrc))
[91326]820 {
[94743]821 RTVFSIOSTREAM hVfsIosEncrypted = NIL_RTVFSIOSTREAM;
822
823#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
824 PCVBOXCRYPTOIF pCryptoIf = NULL;
825 SecretKey *pKey = NULL;
826
827 if ( m->bd->strKeyId.isNotEmpty()
828 && m->bd->strKeyStore.isNotEmpty())
[94912]829 vrc = i_setupEncryptionOrDecryption(hVfsIos, true /*fEncrypt*/,
830 &pCryptoIf, &pKey, &hVfsIosEncrypted);
[94743]831#endif
832
[94912]833 if (RT_SUCCESS(vrc))
[91326]834 {
[94743]835 RTVFSFSSTREAM hVfsFss;
[94912]836 vrc = RTZipTarFsStreamToIoStream( hVfsIosEncrypted != NIL_RTVFSIOSTREAM
837 ? hVfsIosEncrypted
838 : hVfsIos,
839 RTZIPTARFORMAT_GNU, 0 /*fFlags*/, &hVfsFss);
840 if (RT_SUCCESS(vrc))
[91326]841 {
[94743]842 NvramStoreIter it = m->bd->mapNvram.begin();
[91326]843
[94743]844 while (it != m->bd->mapNvram.end())
845 {
846 RTVFSFILE hVfsFile = it->second;
[91326]847
[94912]848 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
849 AssertRC(vrc);
[91326]850
[94743]851 RTVFSOBJ hVfsObj = RTVfsObjFromFile(hVfsFile);
[94912]852 vrc = RTVfsFsStrmAdd(hVfsFss, it->first.c_str(), hVfsObj, 0 /*fFlags*/);
[94743]853 RTVfsObjRelease(hVfsObj);
[94912]854 if (RT_FAILURE(vrc))
[94743]855 break;
856
857 it++;
858 }
859
860 RTVfsFsStrmRelease(hVfsFss);
[91326]861 }
862
[94743]863#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
864 if (hVfsIosEncrypted != NIL_RTVFSIOSTREAM)
865 i_releaseEncryptionOrDecryptionResources(hVfsIosEncrypted, pCryptoIf, pKey);
866#endif
[91326]867 }
868
869 RTVfsIoStrmRelease(hVfsIos);
870 }
871
[94912]872 return vrc;
[91326]873}
874
875
[94743]876int NvramStore::i_retainCryptoIf(PCVBOXCRYPTOIF *ppCryptoIf)
877{
878#ifdef VBOX_COM_INPROC
879 return m->pParent->i_retainCryptoIf(ppCryptoIf);
880#else
[94745]881 HRESULT hrc = m->pParent->i_getVirtualBox()->i_retainCryptoIf(ppCryptoIf);
882 if (SUCCEEDED(hrc))
883 return VINF_SUCCESS;
884
885 return VERR_COM_IPRT_ERROR;
[94743]886#endif
887}
888
889
890int NvramStore::i_releaseCryptoIf(PCVBOXCRYPTOIF pCryptoIf)
891{
892#ifdef VBOX_COM_INPROC
893 return m->pParent->i_releaseCryptoIf(pCryptoIf);
894#else
[94745]895 HRESULT hrc = m->pParent->i_getVirtualBox()->i_releaseCryptoIf(pCryptoIf);
896 if (SUCCEEDED(hrc))
897 return VINF_SUCCESS;
898
899 return VERR_COM_IPRT_ERROR;
[94743]900#endif
901}
902
903
[91326]904/**
905 * Saves the NVRAM store.
906 *
907 * @returns IPRT status code.
908 */
909int NvramStore::i_saveStore(void)
910{
[94912]911 int vrc = VINF_SUCCESS;
[91326]912
[91536]913 Utf8Str strTmp;
914 NvramStore::getNonVolatileStorageFile(strTmp);
915
[93570]916 /*
917 * Only store the NVRAM content if the path is not empty, if it is
[99417]918 * this means the VM was just created and the store was not saved yet,
[93570]919 * see @bugref{10191}.
920 */
921 if (strTmp.isNotEmpty())
[91326]922 {
[93570]923 /*
924 * Skip creating the tar archive if only the UEFI NVRAM content is available in order
925 * to maintain backwards compatibility. As soon as there is more than one entry or
926 * it doesn't belong to the UEFI the tar archive will be created.
927 */
928 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
929 if ( m->bd->mapNvram.size() == 1
[99417]930 && m->bd->mapNvram.begin()->first == "efi/nvram")
[93570]931 {
[99417]932 RTVFSFILE hVfsFileNvram = m->bd->mapNvram.begin()->second;
[91326]933
[94912]934 vrc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
[99417]935 AssertLogRelRC(vrc);
[91326]936
[93570]937 RTVFSIOSTREAM hVfsIosDst;
[94912]938 vrc = RTVfsIoStrmOpenNormal(strTmp.c_str(), RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE,
939 &hVfsIosDst);
940 if (RT_SUCCESS(vrc))
[93570]941 {
942 RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(hVfsFileNvram);
943 Assert(hVfsIosSrc != NIL_RTVFSIOSTREAM);
[91326]944
[94743]945 RTVFSIOSTREAM hVfsIosEncrypted = NIL_RTVFSIOSTREAM;
[91326]946
[94743]947#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
948 PCVBOXCRYPTOIF pCryptoIf = NULL;
949 SecretKey *pKey = NULL;
950
951 if ( m->bd->strKeyId.isNotEmpty()
952 && m->bd->strKeyStore.isNotEmpty())
[94912]953 vrc = i_setupEncryptionOrDecryption(hVfsIosDst, true /*fEncrypt*/,
954 &pCryptoIf, &pKey, &hVfsIosEncrypted);
[94743]955#endif
956
[94912]957 vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc,
958 hVfsIosEncrypted != NIL_RTVFSIOSTREAM
959 ? hVfsIosEncrypted
960 : hVfsIosDst
961 , 0 /*cbBufHint*/);
[94743]962
963#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
964 if (hVfsIosEncrypted != NIL_RTVFSIOSTREAM)
965 i_releaseEncryptionOrDecryptionResources(hVfsIosEncrypted, pCryptoIf, pKey);
966#endif
967
[93570]968 RTVfsIoStrmRelease(hVfsIosSrc);
969 RTVfsIoStrmRelease(hVfsIosDst);
970 }
[91326]971 }
[93570]972 else if (m->bd->mapNvram.size())
[94912]973 vrc = i_saveStoreAsTar(strTmp.c_str());
[93570]974 /* else: No NVRAM content to store so we are done here. */
[91326]975 }
976
[94912]977 return vrc;
[91326]978}
979
980
[94743]981#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
982HRESULT NvramStore::i_updateEncryptionSettings(const com::Utf8Str &strKeyId,
983 const com::Utf8Str &strKeyStore)
984{
985 /* sanity */
986 AutoCaller autoCaller(this);
[98262]987 AssertComRCReturnRC(autoCaller.hrc());
[94743]988
989 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
990
991 m->bd.backup();
992 m->bd->strKeyId = strKeyId;
993 m->bd->strKeyStore = strKeyStore;
994
995 /* clear all passwords because they are invalid now */
996 m->mpKeyStore->deleteAllSecretKeys(false, true);
997
998 alock.release();
999 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
[91326]1000#ifndef VBOX_COM_INPROC
[94743]1001 m->pParent->i_setModified(Machine::IsModified_NvramStore);
1002#endif
1003 return S_OK;
1004}
1005
1006
1007HRESULT NvramStore::i_getEncryptionSettings(com::Utf8Str &strKeyId,
1008 com::Utf8Str &strKeyStore)
1009{
1010 AutoCaller autoCaller(this);
[98262]1011 AssertComRCReturnRC(autoCaller.hrc());
[94743]1012
1013 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1014
1015 strKeyId = m->bd->strKeyId;
1016 strKeyStore = m->bd->strKeyStore;
1017
1018 return S_OK;
1019}
1020
1021
1022int NvramStore::i_addPassword(const Utf8Str &strKeyId, const Utf8Str &strPassword)
1023{
1024 AutoCaller autoCaller(this);
[98262]1025 AssertComRCReturn(autoCaller.hrc(), VERR_INVALID_STATE);
[94743]1026
1027 /* keep only required password */
1028 if (strKeyId != m->bd->strKeyId)
1029 return VINF_SUCCESS;
1030
1031 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1032 return m->mpKeyStore->addSecretKey(strKeyId, (const uint8_t *)strPassword.c_str(), strPassword.length() + 1);
1033}
1034
1035
1036int NvramStore::i_removePassword(const Utf8Str &strKeyId)
1037{
1038 AutoCaller autoCaller(this);
[98262]1039 AssertComRCReturn(autoCaller.hrc(), VERR_INVALID_STATE);
[94743]1040
1041 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1042 return m->mpKeyStore->deleteSecretKey(strKeyId);
1043}
1044
1045
1046int NvramStore::i_removeAllPasswords()
1047{
1048 AutoCaller autoCaller(this);
[98262]1049 AssertComRCReturn(autoCaller.hrc(), VERR_INVALID_STATE);
[94743]1050
1051 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1052 m->mpKeyStore->deleteAllSecretKeys(false, true);
1053 return VINF_SUCCESS;
1054}
1055#endif
1056
1057
1058#ifndef VBOX_COM_INPROC
[99417]1059
[91535]1060HRESULT NvramStore::i_retainUefiVarStore(PRTVFS phVfs, bool fReadonly)
1061{
[103532]1062 /* the machine needs to be mutable unless fReadonly is set */
1063 AutoMutableStateDependency adep(fReadonly ? NULL : m->pParent);
[98262]1064 if (FAILED(adep.hrc())) return adep.hrc();
[91535]1065
1066 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
1067
1068 HRESULT hrc = S_OK;
1069 NvramStoreIter it = m->bd->mapNvram.find("efi/nvram");
1070 if (it != m->bd->mapNvram.end())
1071 {
1072 RTVFSFILE hVfsFileNvram = it->second;
1073 RTVFS hVfsEfiVarStore;
1074 uint32_t fMntFlags = fReadonly ? RTVFSMNT_F_READ_ONLY : 0;
1075
1076 int vrc = RTEfiVarStoreOpenAsVfs(hVfsFileNvram, fMntFlags, 0 /*fVarStoreFlags*/, &hVfsEfiVarStore,
1077 NULL /*pErrInfo*/);
1078 if (RT_SUCCESS(vrc))
1079 {
1080 *phVfs = hVfsEfiVarStore;
1081 if (!fReadonly)
1082 m->pParent->i_setModified(Machine::IsModified_NvramStore);
1083 }
1084 else
1085 hrc = setError(E_FAIL, tr("Opening the UEFI variable store failed (%Rrc)."), vrc);
1086 }
1087 else
1088 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The UEFI NVRAM file is not existing for this machine."));
1089
1090 return hrc;
1091}
1092
1093
1094HRESULT NvramStore::i_releaseUefiVarStore(RTVFS hVfs)
1095{
1096 RTVfsRelease(hVfs);
1097 return S_OK;
1098}
1099
1100
[91326]1101/**
1102 * Loads settings from the given machine node.
1103 * May be called once right after this object creation.
1104 *
1105 * @param data Configuration settings.
1106 *
1107 * @note Locks this object for writing.
1108 */
1109HRESULT NvramStore::i_loadSettings(const settings::NvramSettings &data)
1110{
1111 AutoCaller autoCaller(this);
[98262]1112 AssertComRCReturnRC(autoCaller.hrc());
[91326]1113
1114 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
1115 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1116
1117 m->bd->strNvramPath = data.strNvramPath;
[94743]1118#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1119 m->bd->strKeyId = data.strKeyId;
1120 m->bd->strKeyStore = data.strKeyStore;
1121#endif
[91326]1122
1123 Utf8Str strTmp(m->bd->strNvramPath);
1124 if (strTmp.isNotEmpty())
1125 m->pParent->i_copyPathRelativeToMachine(strTmp, m->bd->strNvramPath);
1126 if ( m->pParent->i_getFirmwareType() == FirmwareType_BIOS
1127 || m->bd->strNvramPath == m->pParent->i_getDefaultNVRAMFilename())
1128 m->bd->strNvramPath.setNull();
1129
1130 return S_OK;
1131}
1132
1133/**
1134 * Saves settings to the given machine node.
1135 *
1136 * @param data Configuration settings.
1137 *
[91434]1138 * @note Locks this object for writing.
[91326]1139 */
1140HRESULT NvramStore::i_saveSettings(settings::NvramSettings &data)
1141{
1142 AutoCaller autoCaller(this);
[98262]1143 AssertComRCReturnRC(autoCaller.hrc());
[91326]1144
[91434]1145 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
[91326]1146
1147 data.strNvramPath = m->bd->strNvramPath;
[94743]1148#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1149 data.strKeyId = m->bd->strKeyId;
1150 data.strKeyStore = m->bd->strKeyStore;
1151#endif
[91326]1152
[91434]1153 int vrc = i_saveStore();
1154 if (RT_FAILURE(vrc))
1155 return setError(E_FAIL, tr("Failed to save the NVRAM content to disk (%Rrc)"), vrc);
1156
[91326]1157 return S_OK;
1158}
1159
1160void NvramStore::i_rollback()
1161{
1162 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1163 m->bd.rollback();
1164}
1165
1166void NvramStore::i_commit()
1167{
1168 /* sanity */
1169 AutoCaller autoCaller(this);
[94912]1170 AssertReturnVoid(autoCaller.isOk());
[91326]1171
1172 /* sanity too */
1173 AutoCaller peerCaller(m->pPeer);
[94912]1174 AssertReturnVoid(peerCaller.isOk());
[91326]1175
1176 /* lock both for writing since we modify both (mPeer is "master" so locked
1177 * first) */
1178 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
1179
1180 if (m->bd.isBackedUp())
1181 {
1182 m->bd.commit();
1183 if (m->pPeer)
1184 {
1185 /* attach new data to the peer and reshare it */
1186 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
1187 m->pPeer->m->bd.attach(m->bd);
1188 }
1189 }
1190}
1191
1192void NvramStore::i_copyFrom(NvramStore *aThat)
1193{
1194 AssertReturnVoid(aThat != NULL);
1195
1196 /* sanity */
1197 AutoCaller autoCaller(this);
[94912]1198 AssertReturnVoid(autoCaller.isOk());
[91326]1199
1200 /* sanity too */
1201 AutoCaller thatCaller(aThat);
[94912]1202 AssertReturnVoid(thatCaller.isOk());
[91326]1203
1204 /* peer is not modified, lock it for reading (aThat is "master" so locked
1205 * first) */
1206 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1207 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1208
1209 /* this will back up current data */
1210 m->bd.assignCopy(aThat->m->bd);
1211
1212 // Intentionally "forget" the NVRAM file since it must be unique and set
1213 // to the correct value before the copy of the settings makes sense.
1214 m->bd->strNvramPath.setNull();
1215}
1216
[91614]1217HRESULT NvramStore::i_applyDefaults(GuestOSType *aOSType)
1218{
1219 HRESULT hrc = S_OK;
1220
1221 if (aOSType->i_recommendedEFISecureBoot())
1222 {
1223 /* Initialize the UEFI variable store and enroll default keys. */
1224 hrc = initUefiVariableStore(0 /*aSize*/);
1225 if (SUCCEEDED(hrc))
1226 {
1227 ComPtr<IUefiVariableStore> pVarStore;
1228
1229 hrc = getUefiVariableStore(pVarStore);
1230 if (SUCCEEDED(hrc))
1231 {
1232 hrc = pVarStore->EnrollOraclePlatformKey();
1233 if (SUCCEEDED(hrc))
1234 hrc = pVarStore->EnrollDefaultMsSignatures();
1235 }
1236 }
1237 }
1238
1239 return hrc;
1240}
1241
[91326]1242void NvramStore::i_updateNonVolatileStorageFile(const Utf8Str &aNonVolatileStorageFile)
1243{
1244 /* sanity */
1245 AutoCaller autoCaller(this);
[98262]1246 AssertComRCReturnVoid(autoCaller.hrc());
[91326]1247
1248 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
1249 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1250
1251 Utf8Str strTmp(aNonVolatileStorageFile);
1252 if (strTmp == m->pParent->i_getDefaultNVRAMFilename())
1253 strTmp.setNull();
1254
1255 if (strTmp == m->bd->strNvramPath)
1256 return;
1257
1258 m->bd.backup();
1259 m->bd->strNvramPath = strTmp;
1260}
1261
[99417]1262#else /* VBOX_COM_INPROC */
1263
[91326]1264//
1265// private methods
1266//
[91346]1267/*static*/
[91326]1268DECLCALLBACK(int) NvramStore::i_nvramStoreQuerySize(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
1269 uint64_t *pcb)
1270{
1271 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1272
[99417]1273 Utf8Str strKey;
1274 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1275 AssertRCReturn(vrc, vrc);
1276
[91326]1277 AutoReadLock rlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
[99417]1278 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(strKey);
[91326]1279 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
1280 {
1281 RTVFSFILE hVfsFile = it->second;
1282 return RTVfsFileQuerySize(hVfsFile, pcb);
1283 }
1284
1285 return VERR_NOT_FOUND;
1286}
1287
1288
[91346]1289/*static*/
[91326]1290DECLCALLBACK(int) NvramStore::i_nvramStoreReadAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
1291 void *pvBuf, size_t cbRead)
1292{
1293 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1294
[99417]1295 Utf8Str strKey;
1296 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1297 AssertRCReturn(vrc, vrc);
1298
[91326]1299 AutoReadLock rlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
[99417]1300 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(strKey);
[91326]1301 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
1302 {
1303 RTVFSFILE hVfsFile = it->second;
1304
[99417]1305 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
1306 AssertLogRelRC(vrc);
[91326]1307
1308 return RTVfsFileRead(hVfsFile, pvBuf, cbRead, NULL /*pcbRead*/);
1309 }
1310
1311 return VERR_NOT_FOUND;
1312}
1313
1314
[91346]1315/*static*/
[91326]1316DECLCALLBACK(int) NvramStore::i_nvramStoreWriteAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
1317 const void *pvBuf, size_t cbWrite)
1318{
1319 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1320
[99417]1321 Utf8Str strKey;
1322 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1323 AssertRCReturn(vrc, vrc);
1324
[91326]1325 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1326
[99417]1327 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(strKey);
[91326]1328 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
1329 {
1330 RTVFSFILE hVfsFile = it->second;
1331
[94912]1332 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
[99417]1333 AssertLogRelRC(vrc);
[94912]1334 vrc = RTVfsFileSetSize(hVfsFile, cbWrite, RTVFSFILE_SIZE_F_NORMAL);
1335 if (RT_SUCCESS(vrc))
1336 vrc = RTVfsFileWrite(hVfsFile, pvBuf, cbWrite, NULL /*pcbWritten*/);
[91326]1337 }
1338 else
1339 {
1340 /* Create a new entry. */
1341 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
[94912]1342 vrc = RTVfsFileFromBuffer(RTFILE_O_READ | RTFILE_O_WRITE, pvBuf, cbWrite, &hVfsFile);
1343 if (RT_SUCCESS(vrc))
[99417]1344 {
1345 try
1346 {
1347 pThis->pNvramStore->m->bd->mapNvram[strKey] = hVfsFile;
1348 }
1349 catch (...)
1350 {
1351 AssertLogRelFailed();
1352 RTVfsFileRelease(hVfsFile);
1353 vrc = VERR_UNEXPECTED_EXCEPTION;
1354 }
1355 }
[91326]1356 }
1357
[94912]1358 return vrc;
[91326]1359}
1360
1361
[91346]1362/*static*/
1363DECLCALLBACK(int) NvramStore::i_nvramStoreDelete(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath)
1364{
1365 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1366
[99417]1367 Utf8Str strKey;
1368 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1369 AssertRCReturn(vrc, vrc);
1370
[91346]1371 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
[99417]1372 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(strKey);
[91346]1373 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
1374 {
1375 RTVFSFILE hVfsFile = it->second;
1376 pThis->pNvramStore->m->bd->mapNvram.erase(it);
1377 RTVfsFileRelease(hVfsFile);
1378 return VINF_SUCCESS;
1379 }
1380
1381 return VERR_NOT_FOUND;
1382}
1383
1384
[94514]1385/*static*/
1386DECLCALLBACK(int) NvramStore::i_SsmSaveExec(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1387{
1388 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1389 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1390 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
1391
1392 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1393
1394 size_t cEntries = pThis->pNvramStore->m->bd->mapNvram.size();
1395 AssertReturn(cEntries < 32, VERR_OUT_OF_RANGE); /* Some sanity checking. */
1396 pHlp->pfnSSMPutU32(pSSM, (uint32_t)cEntries);
1397
1398 void *pvData = NULL;
1399 size_t cbDataMax = 0;
[99417]1400 int vrc = i_SsmSaveExecInner(pThis, pHlp, pSSM, &pvData, &cbDataMax);
1401 if (pvData)
1402 RTMemFree(pvData);
1403 AssertRCReturn(vrc, vrc);
[94514]1404
[99417]1405 pThis->pNvramStore->m->fSsmSaved = true;
1406 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1407}
1408
1409
1410/*static*/
1411int NvramStore::i_SsmSaveExecInner(PDRVMAINNVRAMSTORE pThis, PCPDMDRVHLPR3 pHlp, PSSMHANDLE pSSM,
1412 void **ppvData, size_t *pcbDataMax) RT_NOEXCEPT
1413{
1414 for (NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.begin(); it != pThis->pNvramStore->m->bd->mapNvram.end(); ++it)
[94514]1415 {
1416 RTVFSFILE hVfsFile = it->second;
[99417]1417
[94514]1418 uint64_t cbFile;
[94912]1419 int vrc = RTVfsFileQuerySize(hVfsFile, &cbFile);
1420 AssertRCReturn(vrc, vrc);
[94514]1421 AssertReturn(cbFile < _1M, VERR_OUT_OF_RANGE);
1422
[99417]1423 if (*pcbDataMax < cbFile)
[94514]1424 {
[99417]1425 void *pvNew = RTMemRealloc(*ppvData, cbFile);
1426 AssertPtrReturn(pvNew, VERR_NO_MEMORY);
1427 *ppvData = pvNew;
1428 *pcbDataMax = cbFile;
[94514]1429 }
1430
[99417]1431 vrc = RTVfsFileReadAt(hVfsFile, 0 /*off*/, *ppvData, cbFile, NULL /*pcbRead*/);
[94912]1432 AssertRCReturn(vrc, vrc);
[94514]1433
1434 pHlp->pfnSSMPutStrZ(pSSM, it->first.c_str());
1435 pHlp->pfnSSMPutU64(pSSM, cbFile);
[99417]1436 pHlp->pfnSSMPutMem(pSSM, *ppvData, cbFile);
[94514]1437 }
[99417]1438 return VINF_SUCCESS;
[94514]1439}
1440
1441
1442/*static*/
1443DECLCALLBACK(int) NvramStore::i_SsmLoadExec(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1444{
1445 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1446 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1447 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
1448
1449 AssertMsgReturn(uVersion >= NVRAM_STORE_SAVED_STATE_VERSION, ("%d\n", uVersion),
1450 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1451
1452 if (uPass == SSM_PASS_FINAL)
1453 {
1454 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1455
1456 /* Clear any content first. */
1457 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.begin();
1458 while (it != pThis->pNvramStore->m->bd->mapNvram.end())
1459 {
1460 RTVfsFileRelease(it->second);
1461 it++;
1462 }
1463
1464 pThis->pNvramStore->m->bd->mapNvram.clear();
1465
1466 uint32_t cEntries = 0;
[94912]1467 int vrc = pHlp->pfnSSMGetU32(pSSM, &cEntries);
1468 AssertRCReturn(vrc, vrc);
[94514]1469 AssertReturn(cEntries < 32, VERR_OUT_OF_RANGE);
1470
1471 void *pvData = NULL;
1472 size_t cbDataMax = 0;
[99417]1473 vrc = i_SsmLoadExecInner(pThis, pHlp, pSSM, cEntries, &pvData, &cbDataMax);
1474 if (pvData)
1475 RTMemFree(pvData);
1476 AssertRCReturn(vrc, vrc);
[94514]1477
[99417]1478 /* The marker. */
1479 uint32_t u32;
1480 vrc = pHlp->pfnSSMGetU32(pSSM, &u32);
1481 AssertRCReturn(vrc, vrc);
1482 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1483 }
[94514]1484
[99417]1485 return VINF_SUCCESS;
1486}
[94514]1487
1488
[99417]1489/*static*/
1490int NvramStore::i_SsmLoadExecInner(PDRVMAINNVRAMSTORE pThis, PCPDMDRVHLPR3 pHlp, PSSMHANDLE pSSM,
1491 uint32_t cEntries, void **ppvData, size_t *pcbDataMax) RT_NOEXCEPT
1492{
1493 while (cEntries-- > 0)
1494 {
1495 char szId[_1K]; /* Lazy developer */
1496 int vrc = pHlp->pfnSSMGetStrZ(pSSM, &szId[0], sizeof(szId));
1497 AssertRCReturn(vrc, vrc);
[94514]1498
[99417]1499 uint64_t cbFile = 0;
1500 vrc = pHlp->pfnSSMGetU64(pSSM, &cbFile);
1501 AssertRCReturn(vrc, vrc);
1502 AssertReturn(cbFile < _1M, VERR_OUT_OF_RANGE);
[94514]1503
[99417]1504 if (*pcbDataMax < cbFile)
1505 {
1506 void *pvNew = RTMemRealloc(*ppvData, cbFile);
1507 AssertPtrReturn(pvNew, VERR_NO_MEMORY);
1508 *ppvData = pvNew;
1509 *pcbDataMax = cbFile;
[94514]1510 }
1511
[99417]1512 vrc = pHlp->pfnSSMGetMem(pSSM, *ppvData, cbFile);
1513 AssertRCReturn(vrc, vrc);
[94514]1514
[99417]1515 RTVFSFILE hVfsFile;
1516 vrc = RTVfsFileFromBuffer(RTFILE_O_READWRITE, *ppvData, cbFile, &hVfsFile);
[94912]1517 AssertRCReturn(vrc, vrc);
[99417]1518
1519 try
1520 {
1521 pThis->pNvramStore->m->bd->mapNvram[Utf8Str(szId)] = hVfsFile;
1522 }
1523 catch (...)
1524 {
1525 AssertLogRelFailed();
1526 RTVfsFileRelease(hVfsFile);
1527 return VERR_UNEXPECTED_EXCEPTION;
1528 }
[94514]1529 }
1530
1531 return VINF_SUCCESS;
1532}
1533
1534
[91326]1535/**
1536 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1537 */
1538DECLCALLBACK(void *) NvramStore::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1539{
1540 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1541 PDRVMAINNVRAMSTORE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1542
1543 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1544 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVFSCONNECTOR, &pDrv->IVfs);
1545 return NULL;
1546}
1547
1548
1549/**
1550 * Destruct a NVRAM store driver instance.
1551 *
1552 * @returns VBox status code.
1553 * @param pDrvIns The driver instance data.
1554 */
1555DECLCALLBACK(void) NvramStore::i_drvDestruct(PPDMDRVINS pDrvIns)
1556{
1557 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1558 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1559 LogFlow(("NvramStore::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
1560
1561 if (pThis->pNvramStore)
1562 {
1563 uint32_t cRefs = ASMAtomicDecU32(&pThis->pNvramStore->m->cRefs);
[94514]1564 if ( !cRefs
1565 && !pThis->pNvramStore->m->fSsmSaved)
[91326]1566 {
[99417]1567 try
1568 {
1569 int vrc = pThis->pNvramStore->i_saveStore();
1570 AssertLogRelRC(vrc); /** @todo Disk full error? */
1571 }
1572 catch (...)
1573 {
1574 AssertLogRelFailed();
1575 }
[91326]1576 }
1577 }
1578}
1579
1580
1581/**
1582 * Construct a NVRAM store driver instance.
1583 *
1584 * @copydoc FNPDMDRVCONSTRUCT
1585 */
1586DECLCALLBACK(int) NvramStore::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1587{
1588 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
[93444]1589 RT_NOREF(fFlags, pCfg);
[91326]1590 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1591 LogFlow(("NvramStore::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
1592
1593 /*
1594 * Validate configuration.
1595 */
[93444]1596 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", "");
[91326]1597 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1598 ("Configuration error: Not possible to attach anything to this driver!\n"),
1599 VERR_PDM_DRVINS_NO_ATTACH);
1600
1601 /*
1602 * IBase.
1603 */
1604 pDrvIns->IBase.pfnQueryInterface = NvramStore::i_drvQueryInterface;
1605
1606 pThis->IVfs.pfnQuerySize = NvramStore::i_nvramStoreQuerySize;
1607 pThis->IVfs.pfnReadAll = NvramStore::i_nvramStoreReadAll;
1608 pThis->IVfs.pfnWriteAll = NvramStore::i_nvramStoreWriteAll;
[91346]1609 pThis->IVfs.pfnDelete = NvramStore::i_nvramStoreDelete;
[91326]1610
1611 /*
1612 * Get the NVRAM store object pointer.
1613 */
1614 com::Guid uuid(COM_IIDOF(INvramStore));
1615 pThis->pNvramStore = (NvramStore *)PDMDrvHlpQueryGenericUserObject(pDrvIns, uuid.raw());
1616 if (!pThis->pNvramStore)
1617 {
1618 AssertMsgFailed(("Configuration error: No/bad NVRAM store object!\n"));
1619 return VERR_NOT_FOUND;
1620 }
1621
[94514]1622 /*
1623 * Only the first instance will register the SSM handlers and will do the work on behalf
1624 * of all other NVRAM store driver instances when it comes to SSM.
1625 */
1626 if (pDrvIns->iInstance == 0)
1627 {
[94912]1628 int vrc = PDMDrvHlpSSMRegister(pDrvIns, NVRAM_STORE_SAVED_STATE_VERSION, 0 /*cbGuess*/,
1629 NvramStore::i_SsmSaveExec, NvramStore::i_SsmLoadExec);
1630 if (RT_FAILURE(vrc))
1631 return PDMDrvHlpVMSetError(pDrvIns, vrc, RT_SRC_POS,
[94514]1632 N_("Failed to register the saved state unit for the NVRAM store"));
1633 }
1634
[91326]1635 uint32_t cRefs = ASMAtomicIncU32(&pThis->pNvramStore->m->cRefs);
1636 if (cRefs == 1)
1637 {
[99417]1638 int vrc;
1639 try
1640 {
1641 vrc = pThis->pNvramStore->i_loadStore(pThis->pNvramStore->m->bd->strNvramPath.c_str());
1642 }
1643 catch (...)
1644 {
1645 vrc = VERR_UNEXPECTED_EXCEPTION;
1646 }
[94912]1647 if (RT_FAILURE(vrc))
[91326]1648 {
1649 ASMAtomicDecU32(&pThis->pNvramStore->m->cRefs);
[94912]1650 return PDMDrvHlpVMSetError(pDrvIns, vrc, RT_SRC_POS,
[91326]1651 N_("Failed to load the NVRAM store from the file"));
1652 }
1653 }
1654
1655 return VINF_SUCCESS;
1656}
1657
1658
1659/**
1660 * NVRAM store driver registration record.
1661 */
1662const PDMDRVREG NvramStore::DrvReg =
1663{
1664 /* u32Version */
1665 PDM_DRVREG_VERSION,
1666 /* szName */
1667 "NvramStore",
1668 /* szRCMod */
1669 "",
1670 /* szR0Mod */
1671 "",
1672 /* pszDescription */
1673 "Main NVRAM store driver (Main as in the API).",
1674 /* fFlags */
1675 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1676 /* fClass. */
1677 PDM_DRVREG_CLASS_STATUS,
1678 /* cMaxInstances */
1679 ~0U,
1680 /* cbInstance */
1681 sizeof(DRVMAINNVRAMSTORE),
1682 /* pfnConstruct */
1683 NvramStore::i_drvConstruct,
1684 /* pfnDestruct */
1685 NvramStore::i_drvDestruct,
1686 /* pfnRelocate */
1687 NULL,
1688 /* pfnIOCtl */
1689 NULL,
1690 /* pfnPowerOn */
1691 NULL,
1692 /* pfnReset */
1693 NULL,
1694 /* pfnSuspend */
1695 NULL,
1696 /* pfnResume */
1697 NULL,
1698 /* pfnAttach */
1699 NULL,
1700 /* pfnDetach */
1701 NULL,
1702 /* pfnPowerOff */
1703 NULL,
1704 /* pfnSoftReset */
1705 NULL,
1706 /* u32EndVersion */
1707 PDM_DRVREG_VERSION
1708};
1709
[99417]1710#endif /* VBOX_COM_INPROC */
1711
[91326]1712/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use