VirtualBox

source: vbox/trunk/src/VBox/Devices/Security/DrvTpmEmuTpms.cpp@ 91093

Last change on this file since 91093 was 91093, checked in by vboxsync, 3 years ago

Devices/Security: PoC TPM emulator driver based directly on libtpms (source code backup, not built), bugref:10075 [comments]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.3 KB
Line 
1/* $Id: DrvTpmEmuTpms.cpp 91093 2021-09-02 13:10:45Z vboxsync $ */
2/** @file
3 * TPM emulation driver based on libtpms.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_TCP /** @todo */
23#include <VBox/vmm/pdmdrv.h>
24#include <VBox/vmm/pdmtpmifs.h>
25#include <iprt/assert.h>
26#include <iprt/file.h>
27#include <iprt/mem.h>
28#include <iprt/string.h>
29#include <iprt/semaphore.h>
30#include <iprt/uuid.h>
31#include <iprt/vfs.h>
32#include <iprt/zip.h>
33
34#include <iprt/formats/tpm.h>
35
36#include <libtpms/tpm_library.h>
37#include <libtpms/tpm_error.h>
38#include <libtpms/tpm_tis.h>
39#include <libtpms/tpm_nvfilename.h>
40
41#include <unistd.h>
42#include <stdlib.h>
43
44#include "VBoxDD.h"
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50
51
52/*********************************************************************************************************************************
53* Structures and Typedefs *
54*********************************************************************************************************************************/
55
56/**
57 * TPM emulation driver instance data.
58 *
59 * @implements PDMITPMCONNECTOR
60 */
61typedef struct DRVTPMEMU
62{
63 /** The stream interface. */
64 PDMITPMCONNECTOR ITpmConnector;
65 /** Pointer to the driver instance. */
66 PPDMDRVINS pDrvIns;
67
68 /** The TPM version we are emulating. */
69 TPMVERSION enmVersion;
70 /** The buffer size the TPM advertises. */
71 uint32_t cbBuffer;
72 /** Currently set locality. */
73 uint8_t bLoc;
74
75 /** NVRAM file path. */
76 char *pszNvramPath;
77
78 void *pvNvPermall;
79 size_t cbNvPermall;
80
81 void *pvNvVolatile;
82 size_t cbNvVolatile;
83
84} DRVTPMEMU;
85/** Pointer to the TPM emulator instance data. */
86typedef DRVTPMEMU *PDRVTPMEMU;
87
88/** The special no current locality selected value. */
89#define TPM_NO_LOCALITY_SELECTED 0xff
90
91
92/*********************************************************************************************************************************
93* Global Variables *
94*********************************************************************************************************************************/
95/** Pointer to the (only) instance data in this driver. */
96static PDRVTPMEMU g_pDrvTpmEmuTpms = NULL;
97
98
99/*********************************************************************************************************************************
100* Internal Functions *
101*********************************************************************************************************************************/
102
103/**
104 * Tries to load the NVRAM.
105 *
106 * @returns VBox status code.
107 * @param pThis The emulator driver instance data.
108 */
109static int drvTpmEmuTpmsNvramLoad(PDRVTPMEMU pThis)
110{
111 RTVFSIOSTREAM hVfsIos;
112 uint32_t offError = 0;
113 RTERRINFOSTATIC ErrInfo;
114 int rc = RTVfsChainOpenIoStream(pThis->pszNvramPath, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN,
115 &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
116 if (RT_FAILURE(rc))
117 {
118 if (rc == VERR_FILE_NOT_FOUND) /* First run. */
119 rc = VINF_SUCCESS;
120
121 return rc;
122 }
123
124 RTVFSFSSTREAM hVfsFss = NIL_RTVFSFSSTREAM;
125 rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, &hVfsFss);
126 RTVfsIoStrmRelease(hVfsIos);
127 if (RT_SUCCESS(rc))
128 {
129 /*
130 * Process the stream.
131 */
132 for (;;)
133 {
134 /*
135 * Retrieve the next object.
136 */
137 char *pszName;
138 RTVFSOBJ hVfsObj;
139 rc = RTVfsFsStrmNext(hVfsFss, &pszName, NULL, &hVfsObj);
140 if (RT_FAILURE(rc))
141 {
142 if (rc == VERR_EOF)
143 rc = VINF_SUCCESS;
144 break;
145 }
146
147 RTFSOBJINFO UnixInfo;
148 rc = RTVfsObjQueryInfo(hVfsObj, &UnixInfo, RTFSOBJATTRADD_UNIX);
149 if (RT_SUCCESS(rc))
150 {
151 switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
152 {
153 case RTFS_TYPE_FILE:
154 {
155 void **ppvDataPtr = NULL;
156 size_t *pcbData = NULL;
157 if (!RTStrCmp(pszName, TPM_PERMANENT_ALL_NAME))
158 {
159 ppvDataPtr = &pThis->pvNvPermall;
160 pcbData = &pThis->cbNvPermall;
161 }
162 else if (!RTStrCmp(pszName, TPM_VOLATILESTATE_NAME))
163 {
164 ppvDataPtr = &pThis->pvNvVolatile;
165 pcbData = &pThis->cbNvVolatile;
166 }
167 else
168 rc = VERR_NOT_FOUND;
169
170 if (RT_SUCCESS(rc))
171 {
172 *ppvDataPtr = RTMemAllocZ(UnixInfo.cbObject);
173 if (*ppvDataPtr)
174 {
175 RTVFSIOSTREAM hVfsIosData = RTVfsObjToIoStream(hVfsObj);
176
177 rc = RTVfsIoStrmRead(hVfsIosData, *ppvDataPtr, UnixInfo.cbObject, true /*fBlocking*/, NULL);
178 *pcbData = UnixInfo.cbObject;
179 RTVfsIoStrmRelease(hVfsIosData);
180 }
181 else
182 rc = VERR_NO_MEMORY;
183 }
184 break;
185 }
186 default:
187 rc = VERR_NOT_SUPPORTED;
188 break;
189 }
190 }
191
192 /*
193 * Release the current object and string.
194 */
195 RTVfsObjRelease(hVfsObj);
196 RTStrFree(pszName);
197
198 if (RT_FAILURE(rc))
199 break;
200 }
201 }
202
203 return rc;
204}
205
206
207static int drvTpmEmuTpmsNvramStoreEntity(RTVFSFSSTREAM hVfsFss, const char *pszName, const void *pvData, size_t cbData)
208{
209 RTVFSIOSTREAM hVfsIosData;
210
211 int rc = RTVfsIoStrmFromBuffer(RTFILE_O_READ, pvData, cbData, &hVfsIosData);
212 if (RT_SUCCESS(rc))
213 {
214 RTVFSOBJ hVfsObj = RTVfsObjFromIoStream(hVfsIosData);
215 rc = RTVfsFsStrmAdd(hVfsFss, pszName, hVfsObj, 0 /*fFlags*/);
216 RTVfsObjRelease(hVfsObj);
217
218 RTVfsIoStrmRelease(hVfsIosData);
219 }
220
221 return rc;
222}
223
224
225/**
226 * Stores the NVRAM content.
227 *
228 * @returns VBox status code.
229 * @param pThis The emulator driver instance data.
230 */
231static int drvTpmEmuTpmsNvramStore(PDRVTPMEMU pThis)
232{
233 uint32_t offError = 0;
234 RTERRINFOSTATIC ErrInfo;
235 RTVFSIOSTREAM hVfsIos;
236
237 int rc = RTVfsChainOpenIoStream(pThis->pszNvramPath, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
238 &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
239 if (RT_SUCCESS(rc))
240 {
241 RTVFSFSSTREAM hVfsFss;
242 rc = RTZipTarFsStreamToIoStream(hVfsIos, RTZIPTARFORMAT_GNU, 0 /*fFlags*/, &hVfsFss);
243 if (RT_SUCCESS(rc))
244 {
245 rc = drvTpmEmuTpmsNvramStoreEntity(hVfsFss, TPM_PERMANENT_ALL_NAME, pThis->pvNvPermall, pThis->cbNvPermall);
246 if (RT_SUCCESS(rc) && pThis->pvNvVolatile)
247 rc = drvTpmEmuTpmsNvramStoreEntity(hVfsFss, TPM_VOLATILESTATE_NAME, pThis->pvNvVolatile, pThis->cbNvVolatile);
248
249 RTVfsFsStrmRelease(hVfsFss);
250 }
251
252 RTVfsIoStrmRelease(hVfsIos);
253 }
254
255 return rc;
256}
257
258
259/** @interface_method_impl{PDMITPMCONNECTOR,pfnStartup} */
260static DECLCALLBACK(int) drvTpmEmuTpmsStartup(PPDMITPMCONNECTOR pInterface)
261{
262 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
263
264 TPM_RESULT rcTpm = TPMLIB_MainInit();
265 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
266 return VINF_SUCCESS;
267
268 LogRel(("DrvTpmEmuTpms#%u: Failed to initialize TPM emulation with %#x\n",
269 pThis->pDrvIns->iInstance, rcTpm));
270 return VERR_DEV_IO_ERROR;
271}
272
273
274/** @interface_method_impl{PDMITPMCONNECTOR,pfnShutdown} */
275static DECLCALLBACK(int) drvTpmEmuTpmsShutdown(PPDMITPMCONNECTOR pInterface)
276{
277 RT_NOREF(pInterface);
278
279 TPMLIB_Terminate();
280 return VINF_SUCCESS;
281}
282
283
284/** @interface_method_impl{PDMITPMCONNECTOR,pfnReset} */
285static DECLCALLBACK(int) drvTpmEmuTpmsReset(PPDMITPMCONNECTOR pInterface)
286{
287 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
288
289 TPMLIB_Terminate();
290 TPM_RESULT rcTpm = TPMLIB_MainInit();
291 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
292 return VINF_SUCCESS;
293
294
295 LogRel(("DrvTpmEmuTpms#%u: Failed to reset TPM emulation with %#x\n",
296 pThis->pDrvIns->iInstance, rcTpm));
297 return VERR_DEV_IO_ERROR;
298}
299
300
301/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetVersion} */
302static DECLCALLBACK(TPMVERSION) drvTpmEmuTpmsGetVersion(PPDMITPMCONNECTOR pInterface)
303{
304 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
305 return pThis->enmVersion;
306}
307
308
309/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetLocalityMax} */
310static DECLCALLBACK(uint32_t) drvTpmEmuGetLocalityMax(PPDMITPMCONNECTOR pInterface)
311{
312 RT_NOREF(pInterface);
313 return 4;
314}
315
316
317/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetBufferSize} */
318static DECLCALLBACK(uint32_t) drvTpmEmuGetBufferSize(PPDMITPMCONNECTOR pInterface)
319{
320 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
321 return pThis->cbBuffer;
322}
323
324
325/** @interface_method_impl{PDMITPMCONNECTOR,pfnGetEstablishedFlag} */
326static DECLCALLBACK(bool) drvTpmEmuTpmsGetEstablishedFlag(PPDMITPMCONNECTOR pInterface)
327{
328 RT_NOREF(pInterface);
329
330 TPM_BOOL fTpmEst = FALSE;
331 TPM_RESULT rcTpm = TPM_IO_TpmEstablished_Get(&fTpmEst);
332 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
333 return RT_BOOL(fTpmEst);
334
335 return false;
336}
337
338
339/** @interface_method_impl{PDMITPMCONNECTOR,pfnResetEstablishedFlag} */
340static DECLCALLBACK(int) drvTpmEmuTpmsResetEstablishedFlag(PPDMITPMCONNECTOR pInterface, uint8_t bLoc)
341{
342 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
343 uint8_t bLocOld = pThis->bLoc;
344
345 pThis->bLoc = bLoc;
346 TPM_RESULT rcTpm = TPM_IO_TpmEstablished_Reset();
347 pThis->bLoc = bLocOld;
348
349 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
350 return VINF_SUCCESS;
351
352 LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to reset the established flag with %#x\n",
353 pThis->pDrvIns->iInstance, rcTpm));
354 return VERR_DEV_IO_ERROR;
355}
356
357
358/** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdExec} */
359static DECLCALLBACK(int) drvTpmEmuTpmsCmdExec(PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)
360{
361 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
362
363 pThis->bLoc = bLoc;
364
365 uint8_t *pbRespBuf = NULL;
366 uint32_t cbRespBuf = 0;
367 uint32_t cbRespActual = 0;
368 TPM_RESULT rcTpm = TPMLIB_Process(&pbRespBuf, &cbRespActual, &cbRespBuf, (uint8_t *)pvCmd, cbCmd);
369 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
370 {
371 memcpy(pvResp, pbRespBuf, RT_MIN(cbResp, cbRespActual));
372 free(pbRespBuf);
373 return VINF_SUCCESS;
374 }
375
376 LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to execute command with %#x\n",
377 pThis->pDrvIns->iInstance, rcTpm));
378 return VERR_DEV_IO_ERROR;
379}
380
381
382/** @interface_method_impl{PDMITPMCONNECTOR,pfnCmdCancel} */
383static DECLCALLBACK(int) drvTpmEmuTpmsCmdCancel(PPDMITPMCONNECTOR pInterface)
384{
385 PDRVTPMEMU pThis = RT_FROM_MEMBER(pInterface, DRVTPMEMU, ITpmConnector);
386
387 TPM_RESULT rcTpm = TPMLIB_CancelCommand();
388 if (RT_LIKELY(rcTpm == TPM_SUCCESS))
389 return VINF_SUCCESS;
390
391 LogRelMax(10, ("DrvTpmEmuTpms#%u: Failed to cancel outstanding command with %#x\n",
392 pThis->pDrvIns->iInstance, rcTpm));
393 return VERR_DEV_IO_ERROR;
394}
395
396
397/** @interface_method_impl{PDMIBASE,pfnQueryInterface} */
398static DECLCALLBACK(void *) drvTpmEmuTpmsQueryInterface(PPDMIBASE pInterface, const char *pszIID)
399{
400 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
401 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
402 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
403 PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMCONNECTOR, &pThis->ITpmConnector);
404 return NULL;
405}
406
407
408/* -=-=-=-=- libtpms_callbacks -=-=-=-=- */
409
410
411static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamInit(void)
412{
413 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
414 RT_NOREF(pThis);
415
416 return TPM_SUCCESS;
417}
418
419
420static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamLoadData(uint8_t **ppvData, uint32_t *pcbLength,
421 uint32_t idTpm, const char *pszName)
422{
423 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
424
425 AssertReturn(idTpm == 0, TPM_FAIL);
426
427 void *pvDataPtr = NULL;
428 size_t cbData = 0;
429 if (!RTStrCmp(pszName, TPM_PERMANENT_ALL_NAME))
430 {
431 pvDataPtr = pThis->pvNvPermall;
432 cbData = pThis->cbNvPermall;
433 }
434 else if (!RTStrCmp(pszName, TPM_VOLATILESTATE_NAME))
435 {
436 pvDataPtr = pThis->pvNvVolatile;
437 cbData = pThis->cbNvVolatile;
438 }
439 else
440 return TPM_FAIL;
441
442 if (pvDataPtr)
443 {
444 *ppvData = (uint8_t *)malloc(cbData);
445 if (*ppvData)
446 {
447 memcpy(*ppvData, pvDataPtr, cbData);
448 *pcbLength = (uint32_t)cbData;
449 return TPM_SUCCESS;
450 }
451
452 return TPM_FAIL;
453 }
454
455 return TPM_RETRY;
456}
457
458
459static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamStoreData(const uint8_t *pvData, uint32_t cbLength,
460 uint32_t idTpm, const char *pszName)
461{
462 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
463
464 AssertReturn(idTpm == 0, TPM_FAIL);
465
466 void **ppvDataPtr = NULL;
467 size_t *pcbData = NULL;
468 if (!RTStrCmp(pszName, TPM_PERMANENT_ALL_NAME))
469 {
470 ppvDataPtr = &pThis->pvNvPermall;
471 pcbData = &pThis->cbNvPermall;
472 }
473 else if (!RTStrCmp(pszName, TPM_VOLATILESTATE_NAME))
474 {
475 ppvDataPtr = &pThis->pvNvVolatile;
476 pcbData = &pThis->cbNvVolatile;
477 }
478 else
479 return TPM_FAIL;
480
481 if ( *ppvDataPtr
482 && *pcbData == cbLength)
483 {
484 memcpy(*ppvDataPtr, pvData, cbLength);
485 return TPM_SUCCESS;
486 }
487 else
488 {
489 if (*ppvDataPtr)
490 RTMemFree(*ppvDataPtr);
491
492 *ppvDataPtr = RTMemDup(pvData, cbLength);
493 if (*ppvDataPtr)
494 {
495 *pcbData = cbLength;
496 return TPM_SUCCESS;
497 }
498 }
499
500 return TPM_FAIL;
501}
502
503
504static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkNvRamDeleteName(uint32_t idTpm, const char *pszName, TPM_BOOL fMustExist)
505{
506 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
507
508 AssertReturn(idTpm == 0, TPM_FAIL);
509
510 void **ppvDataPtr = NULL;
511 size_t *pcbData = NULL;
512 if (!RTStrCmp(pszName, TPM_PERMANENT_ALL_NAME))
513 {
514 ppvDataPtr = &pThis->pvNvPermall;
515 pcbData = &pThis->cbNvPermall;
516 }
517 else if (!RTStrCmp(pszName, TPM_VOLATILESTATE_NAME))
518 {
519 ppvDataPtr = &pThis->pvNvVolatile;
520 pcbData = &pThis->cbNvVolatile;
521 }
522 else
523 return TPM_SUCCESS;
524
525 if (*ppvDataPtr)
526 {
527 RTMemFree(*ppvDataPtr);
528 *ppvDataPtr = NULL;
529 *pcbData = 0;
530 }
531 else if (fMustExist)
532 return TPM_FAIL;
533
534 return TPM_SUCCESS;
535}
536
537
538static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoInit(void)
539{
540 return TPM_SUCCESS;
541}
542
543
544static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoGetLocality(TPM_MODIFIER_INDICATOR *pLocalityModifier, uint32_t idTpm)
545{
546 PDRVTPMEMU pThis = g_pDrvTpmEmuTpms;
547
548 AssertReturn(idTpm == 0, TPM_FAIL);
549
550 *pLocalityModifier = pThis->bLoc;
551 return TPM_SUCCESS;
552}
553
554
555static DECLCALLBACK(TPM_RESULT) drvTpmEmuTpmsCbkIoGetPhysicalPresence(TPM_BOOL *pfPhysicalPresence, uint32_t idTpm)
556{
557 AssertReturn(idTpm == 0, TPM_FAIL);
558
559 *pfPhysicalPresence = TRUE;
560 return TPM_SUCCESS;
561}
562
563
564/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
565
566/** @copydoc FNPDMDRVDESTRUCT */
567static DECLCALLBACK(void) drvTpmEmuTpmsDestruct(PPDMDRVINS pDrvIns)
568{
569 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
570
571 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
572 LogFlow(("%s\n", __FUNCTION__));
573
574 int rc = drvTpmEmuTpmsNvramStore(pThis);
575 AssertRC(rc);
576
577 if (pThis->pvNvPermall)
578 {
579 RTMemFree(pThis->pvNvPermall);
580 pThis->pvNvPermall = NULL;
581 }
582
583 if (pThis->pvNvVolatile)
584 {
585 RTMemFree(pThis->pvNvVolatile);
586 pThis->pvNvVolatile = NULL;
587 }
588
589#if 0
590 if (pThis->pszNvramPath)
591 {
592 PDMDrvHlpMMHeapFree(pDrvIns, pThis->pszNvramPath);
593 pThisCC->pszNvramPath = NULL;
594 }
595#endif
596}
597
598
599/** @copydoc FNPDMDRVCONSTRUCT */
600static DECLCALLBACK(int) drvTpmEmuTpmsConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
601{
602 RT_NOREF(fFlags);
603 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
604 PDRVTPMEMU pThis = PDMINS_2_DATA(pDrvIns, PDRVTPMEMU);
605
606 /*
607 * Init the static parts.
608 */
609 pThis->pDrvIns = pDrvIns;
610 pThis->enmVersion = TPMVERSION_UNKNOWN;
611 pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
612 pThis->pvNvPermall = NULL;
613 pThis->cbNvPermall = 0;
614 pThis->pvNvVolatile = NULL;
615 pThis->cbNvVolatile = 0;
616
617 /* IBase */
618 pDrvIns->IBase.pfnQueryInterface = drvTpmEmuTpmsQueryInterface;
619 /* ITpmConnector */
620 pThis->ITpmConnector.pfnStartup = drvTpmEmuTpmsStartup;
621 pThis->ITpmConnector.pfnShutdown = drvTpmEmuTpmsShutdown;
622 pThis->ITpmConnector.pfnReset = drvTpmEmuTpmsReset;
623 pThis->ITpmConnector.pfnGetVersion = drvTpmEmuTpmsGetVersion;
624 pThis->ITpmConnector.pfnGetLocalityMax = drvTpmEmuGetLocalityMax;
625 pThis->ITpmConnector.pfnGetBufferSize = drvTpmEmuGetBufferSize;
626 pThis->ITpmConnector.pfnGetEstablishedFlag = drvTpmEmuTpmsGetEstablishedFlag;
627 pThis->ITpmConnector.pfnResetEstablishedFlag = drvTpmEmuTpmsResetEstablishedFlag;
628 pThis->ITpmConnector.pfnCmdExec = drvTpmEmuTpmsCmdExec;
629 pThis->ITpmConnector.pfnCmdCancel = drvTpmEmuTpmsCmdCancel;
630
631 /*
632 * Validate and read the configuration.
633 */
634 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "TpmVersion|BufferSize|NvramPath", "");
635
636 TPMLIB_SetDebugFD(STDERR_FILENO);
637 TPMLIB_SetDebugLevel(~0);
638
639 int rc = CFGMR3QueryStringAlloc(pCfg, "NvramPath", &pThis->pszNvramPath);
640 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
641 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
642 N_("Configuration error: querying \"NvramPath\" resulted in %Rrc"), rc);
643
644 rc = drvTpmEmuTpmsNvramLoad(pThis);
645 if (RT_FAILURE(rc))
646 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
647 N_("Failed to load TPM NVRAM data with %Rrc"), rc);
648
649 TPMLIB_TPMVersion enmVersion = TPMLIB_TPM_VERSION_2;
650 uint32_t uTpmVersion = 0;
651 rc = CFGMR3QueryU32Def(pCfg, "TpmVersion", &uTpmVersion, 2);
652 if (RT_FAILURE(rc))
653 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
654 N_("Configuration error: querying \"TpmVersion\" resulted in %Rrc"), rc);
655
656 switch (uTpmVersion)
657 {
658 case 1:
659 enmVersion = TPMLIB_TPM_VERSION_1_2;
660 pThis->enmVersion = TPMVERSION_1_2;
661 break;
662 case 2:
663 enmVersion = TPMLIB_TPM_VERSION_2;
664 pThis->enmVersion = TPMVERSION_2_0;
665 break;
666 default:
667 return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_SUPPORTED, RT_SRC_POS,
668 N_("Configuration error: \"TpmVersion\" %u is not supported"), uTpmVersion);
669 }
670
671 TPM_RESULT rcTpm = TPMLIB_ChooseTPMVersion(enmVersion);
672 if (rcTpm != TPM_SUCCESS)
673 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
674 N_("Failed to set the TPM version for the emulated TPM with %d"), rcTpm);
675
676 int cbBufferMax = 0;
677 rcTpm = TPMLIB_GetTPMProperty(TPMPROP_TPM_BUFFER_MAX, &cbBufferMax);
678 if (rcTpm != TPM_SUCCESS)
679 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
680 N_("Querying the maximum supported buffer size failed with %u"), rcTpm);
681
682 rc = CFGMR3QueryU32Def(pCfg, "BufferSize", &pThis->cbBuffer, (uint32_t)cbBufferMax);
683 if (RT_FAILURE(rc))
684 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
685 N_("Configuration error: querying \"BufferSize\" resulted in %Rrc"), rc);
686
687 uint32_t cbBufferMin = 0;
688 uint32_t cbBuffer = TPMLIB_SetBufferSize(pThis->cbBuffer, &cbBufferMin, NULL /*max_size*/);
689 if (pThis->cbBuffer != cbBuffer)
690 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
691 N_("Failed to set buffer size (%u) of the emulated TPM with %u (min %u, max %d)"),
692 pThis->cbBuffer, cbBuffer, cbBufferMin, cbBufferMax);
693
694 struct libtpms_callbacks Callbacks;
695 Callbacks.sizeOfStruct = sizeof(Callbacks);
696 Callbacks.tpm_nvram_init = drvTpmEmuTpmsCbkNvRamInit;
697 Callbacks.tpm_nvram_loaddata = drvTpmEmuTpmsCbkNvRamLoadData;
698 Callbacks.tpm_nvram_storedata = drvTpmEmuTpmsCbkNvRamStoreData;
699 Callbacks.tpm_nvram_deletename = drvTpmEmuTpmsCbkNvRamDeleteName;
700 Callbacks.tpm_io_init = drvTpmEmuTpmsCbkIoInit;
701 Callbacks.tpm_io_getlocality = drvTpmEmuTpmsCbkIoGetLocality;
702 Callbacks.tpm_io_getphysicalpresence = drvTpmEmuTpmsCbkIoGetPhysicalPresence;
703 rcTpm = TPMLIB_RegisterCallbacks(&Callbacks);
704 if (rcTpm != TPM_SUCCESS)
705 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
706 N_("Failed to register callbacks with the TPM emulation: %u"),
707 rcTpm);
708
709 /* We can only have one instance of the TPM emulation and require the global variable for the callbacks unfortunately. */
710 g_pDrvTpmEmuTpms = pThis;
711 return VINF_SUCCESS;
712}
713
714
715/**
716 * TPM libtpms emulator driver registration record.
717 */
718const PDMDRVREG g_DrvTpmEmuTpms =
719{
720 /* u32Version */
721 PDM_DRVREG_VERSION,
722 /* szName */
723 "TpmEmuTpms",
724 /* szRCMod */
725 "",
726 /* szR0Mod */
727 "",
728 /* pszDescription */
729 "TPM emulation driver based on libtpms.",
730 /* fFlags */
731 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
732 /* fClass. */
733 PDM_DRVREG_CLASS_STREAM,
734 /* cMaxInstances */
735 1,
736 /* cbInstance */
737 sizeof(DRVTPMEMU),
738 /* pfnConstruct */
739 drvTpmEmuTpmsConstruct,
740 /* pfnDestruct */
741 drvTpmEmuTpmsDestruct,
742 /* pfnRelocate */
743 NULL,
744 /* pfnIOCtl */
745 NULL,
746 /* pfnPowerOn */
747 NULL,
748 /* pfnReset */
749 NULL,
750 /* pfnSuspend */
751 NULL,
752 /* pfnResume */
753 NULL,
754 /* pfnAttach */
755 NULL,
756 /* pfnDetach */
757 NULL,
758 /* pfnPowerOff */
759 NULL,
760 /* pfnSoftReset */
761 NULL,
762 /* u32EndVersion */
763 PDM_DRVREG_VERSION
764};
765
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