1 /* Microsoft Reference Implementation for TPM 2.0
2  *
3  *  The copyright in this software is being made available under the BSD License,
4  *  included below. This software may be subject to other third party and
5  *  contributor rights, including patent rights, and no such rights are granted
6  *  under this license.
7  *
8  *  Copyright (c) Microsoft Corporation
9  *
10  *  All rights reserved.
11  *
12  *  BSD License
13  *
14  *  Redistribution and use in source and binary forms, with or without modification,
15  *  are permitted provided that the following conditions are met:
16  *
17  *  Redistributions of source code must retain the above copyright notice, this list
18  *  of conditions and the following disclaimer.
19  *
20  *  Redistributions in binary form must reproduce the above copyright notice, this
21  *  list of conditions and the following disclaimer in the documentation and/or
22  *  other materials provided with the distribution.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28  *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 //** Description
36 //
37 //    This file contains the NV read and write access methods.  This implementation
38 //    uses RAM/file and does not manage the RAM/file as NV blocks.
39 //    The implementation may become more sophisticated over time.
40 //
41 
42 #include "TpmError.h"
43 #include "Admin.h"
44 #include "VendorString.h"
45 #include "stdint.h"
46 #include "malloc.h"
47 #include "string.h"
48 
49 #include <tee_internal_api.h>
50 #include <tee_internal_api_extensions.h>
51 
52 //
53 // Overall size of NV, not just the TPM's NV storage
54 //
55 #define NV_CHIP_MEMORY_SIZE	(NV_MEMORY_SIZE + NV_TPM_STATE_SIZE)
56 
57 //
58 // OpTEE still has an all or nothing approach to reads/writes. To provide
59 // more performant access to storage, break up NV accross 1Kbyte blocks.
60 //
61 // Note that NV_CHIP_MEMORY_SIZE *MUST* be a factor of NV_BLOCK_SIZE.
62 //
63 #define NV_BLOCK_SIZE        0x200
64 #define NV_BLOCK_COUNT      ((NV_CHIP_MEMORY_SIZE) / (NV_BLOCK_SIZE))
65 
66 //
67 // For cleaner descriptor validation
68 //
69 #define IS_VALID(a) ((a) != (TEE_HANDLE_NULL))
70 
71 //
72 // Storage flags
73 //
74 #define TA_STORAGE_FLAGS (TEE_DATA_FLAG_ACCESS_READ  | \
75                           TEE_DATA_FLAG_ACCESS_WRITE | \
76                           TEE_DATA_FLAG_ACCESS_WRITE_META)
77 
78 //
79 // The base Object ID for fTPM storage
80 //
81 static const UINT32 s_StorageObjectID = 0x54504D00;	// 'TPM00'
82 
83 //
84 // Object handle list for persistent storage objects containing NV
85 //
86 static TEE_ObjectHandle s_NVStore[NV_BLOCK_COUNT] = { TEE_HANDLE_NULL };
87 
88 //
89 // Bitmap for NV blocks. Moving from UINT64 requires change to NV_DIRTY_ALL.
90 //
91 static UINT64 s_blockMap = 0x0ULL;
92 
93 //
94 // Shortcut for 'dirty'ing all NV blocks. Note the type.
95 //
96 #if NV_BLOCK_COUNT < 64
97 #define NV_DIRTY_ALL	((UINT64)((0x1ULL << NV_BLOCK_COUNT) - 1))
98 #elif NV_BLOCK_COUNT == 64
99 #define NV_DIRTY_ALL    (~(0x0ULL))
100 #else
101 #error "NV block count exceeds 64 bit block map. Adjust block or NV size."
102 #endif
103 
104 //
105 // NV state
106 //
107 static BOOL  s_NVChipFileNeedsManufacture = FALSE;
108 static BOOL  s_NVInitialized = FALSE;
109 static UCHAR s_NV[NV_CHIP_MEMORY_SIZE];
110 
111 //
112 // Firmware revision
113 //
114 static const UINT32 firmwareV1 = FIRMWARE_V1;
115 static const UINT32 firmwareV2 = FIRMWARE_V2;
116 
117 //
118 // Revision fro NVChip
119 //
120 static UINT64 s_chipRevision = 0;
121 
122 //
123 // This offset puts the revision field immediately following the TPM Admin
124 // state. The Admin space in NV is down to ~16 bytes but is padded out to
125 // 256bytes to avoid alignment issues and allow for growth.
126 //
127 #define NV_CHIP_REVISION_OFFSET ((NV_MEMORY_SIZE) + (TPM_STATE_SIZE))
128 
129 VOID
_plat__NvInitFromStorage()130 _plat__NvInitFromStorage()
131 {
132 	DMSG("_plat__NvInitFromStorage()");
133 	UINT32 i;
134 	BOOL initialized;
135 	UINT32 objID;
136 	UINT32 bytesRead;
137 	TEE_Result Result;
138 
139 	// Don't re-initialize.
140 	if (s_NVInitialized) {
141 		return;
142 	}
143 
144 	//
145 	// If the NV file is successfully read from the storage then
146 	// initialized must be set. We are setting initialized to true
147 	// here but if an error is encountered reading the NV file it will
148 	// be reset.
149 	//
150 
151 	initialized = TRUE;
152 
153 	// Collect storage objects and init NV.
154 	for (i = 0; i < NV_BLOCK_COUNT; i++) {
155 
156 		// Form storage object ID for this block.
157 		objID = s_StorageObjectID + i;
158 
159 		// Attempt to open TEE persistent storage object.
160 		Result = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
161 									      (void *)&objID,
162 									      sizeof(objID),
163 									      TA_STORAGE_FLAGS,
164 									      &s_NVStore[i]);
165 
166 		// If the open failed, try to create this storage object.
167 		if (Result != TEE_SUCCESS) {
168 
169 			// There was an error, fail the init, NVEnable can retry.
170 			if (Result != TEE_ERROR_ITEM_NOT_FOUND) {
171 #ifdef fTPMDebug
172 				DMSG("Failed to open fTPM storage object");
173 #endif
174 				goto Error;
175 			}
176 
177 			// Storage object was not found, create it.
178 			Result = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
179 										        (void *)&objID,
180 										        sizeof(objID),
181 										        TA_STORAGE_FLAGS,
182 										        NULL,
183 										        (void *)&(s_NV[i * NV_BLOCK_SIZE]),
184 										        NV_BLOCK_SIZE,
185 										        &s_NVStore[i]);
186 
187 			// There was an error, fail the init, NVEnable can retry.
188 			if (Result != TEE_SUCCESS) {
189 #ifdef fTPMDebug
190 				DMSG("Failed to create fTPM storage object");
191 #endif
192 				goto Error;
193 			}
194 
195 			// A clean storage object was created, we must (re)manufacture.
196 			s_NVChipFileNeedsManufacture = TRUE;
197 
198 			// To ensure NV is consistent, force a write back of all NV blocks
199 			s_blockMap = NV_DIRTY_ALL;
200 
201 			// Need to re-initialize
202 			initialized = FALSE;
203 
204 #ifdef fTPMDebug
205 			IMSG("Created fTPM storage object, i: 0x%x, s: 0x%x, id: 0x%x, h:0x%x\n",
206 				i, NV_BLOCK_SIZE, objID, s_NVStore[i]);
207 #endif
208 		}
209 		else {
210 			// Successful open, now read fTPM storage object.
211 			Result = TEE_ReadObjectData(s_NVStore[i],
212 										(void *)&(s_NV[i * NV_BLOCK_SIZE]),
213 										NV_BLOCK_SIZE,
214 										&bytesRead);
215 
216 			// Give up on failed or incomplete reads.
217 			if ((Result != TEE_SUCCESS) || (bytesRead != NV_BLOCK_SIZE)) {
218 #ifdef fTPMDebug
219 				DMSG("Failed to read fTPM storage object");
220 #endif
221 				goto Error;
222 			}
223 
224 #ifdef fTPMDebug
225 			IMSG("Read fTPM storage object, i: 0x%x, s: 0x%x, id: 0x%x, h:0x%x\n",
226 				i, bytesRead, objID, s_NVStore[i]);
227 #endif
228 		}
229 	}
230 
231 	// Storage objects are open and valid, next validate revision
232 	s_chipRevision = ((((UINT64)firmwareV2) << 32) | (firmwareV1));
233 	if ((s_chipRevision != *(UINT64*)&(s_NV[NV_CHIP_REVISION_OFFSET]))) {
234 
235 		// Failure to validate revision, re-init.
236 		memset(s_NV, 0, NV_CHIP_MEMORY_SIZE);
237 
238 		// Dirty the block map, we're going to re-init.
239 		s_blockMap = NV_DIRTY_ALL;
240 
241 		// Init with proper revision
242 		s_chipRevision = ((((UINT64)firmwareV2) << 32) | (firmwareV1));
243 		*(UINT64*)&(s_NV[NV_CHIP_REVISION_OFFSET]) = s_chipRevision;
244 
245 #ifdef fTPMDebug
246 		DMSG("Failed to validate revision.");
247 #endif
248 
249 		// Force (re)manufacture.
250 		s_NVChipFileNeedsManufacture = TRUE;
251 
252 		// Need to re-initialize
253 		initialized = FALSE;
254 
255 		return;
256 	}
257 
258 	s_NVInitialized = initialized;
259 
260 	return;
261 
262 Error:
263 	s_NVInitialized = FALSE;
264 	for (i = 0; i < NV_BLOCK_COUNT; i++) {
265 		if (IS_VALID(s_NVStore[i])) {
266 			TEE_CloseObject(s_NVStore[i]);
267 			s_NVStore[i] = TEE_HANDLE_NULL;
268 		}
269 	}
270 
271 	return;
272 }
273 
274 
275 static void
_plat__NvWriteBack()276 _plat__NvWriteBack()
277 {
278     UINT32 i;
279 	UINT32 objID;
280 	TEE_Result Result;
281 
282 	// Exit if no dirty blocks.
283 	if ((!s_blockMap) || (!s_NVInitialized)) {
284 		return;
285 	}
286 
287 #ifdef fTPMDebug
288 	DMSG("bMap: 0x%x\n", s_blockMap);
289 #endif
290 
291 	// Write dirty blocks.
292     for (i = 0; i < NV_BLOCK_COUNT; i++) {
293 
294         if ((s_blockMap & (0x1ULL << i))) {
295 
296 			// Form storage object ID for this block.
297 			objID = s_StorageObjectID + i;
298 
299 			// Move data position associated with handle to start of block.
300             Result = TEE_SeekObjectData(s_NVStore[i], 0, TEE_DATA_SEEK_SET);
301 			if (Result != TEE_SUCCESS) {
302 				goto Error;
303 			}
304 
305 			// Write out this block.
306             Result = TEE_WriteObjectData(s_NVStore[i],
307 									     (void *)&(s_NV[i * NV_BLOCK_SIZE]),
308                                          NV_BLOCK_SIZE);
309 			if (Result != TEE_SUCCESS) {
310 				goto Error;
311 			}
312 
313 			// Force storage stack to update its backing store
314             TEE_CloseObject(s_NVStore[i]);
315 
316             Result = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
317                                               (void *)&objID,
318                                               sizeof(objID),
319                                               TA_STORAGE_FLAGS,
320                                               &s_NVStore[i]);
321 			// Success?
322 			if (Result != TEE_SUCCESS) {
323 				goto Error;
324 			}
325 
326 			// Clear dirty bit.
327             s_blockMap &= ~(0x1ULL << i);
328         }
329     }
330 
331     return;
332 
333 Error:
334 	// Error path.
335 #ifdef fTPMDebug
336 	DMSG("NV write back failed");
337 #endif
338 	s_NVInitialized = FALSE;
339 	for (i = 0; i < NV_BLOCK_COUNT; i++) {
340 		if (IS_VALID(s_NVStore[i])) {
341 			TEE_CloseObject(s_NVStore[i]);
342 			s_NVStore[i] = TEE_HANDLE_NULL;
343 		}
344 	}
345 
346 	return;
347 }
348 
349 
350 BOOL
_plat__NvNeedsManufacture()351 _plat__NvNeedsManufacture()
352 {
353     return s_NVChipFileNeedsManufacture;
354 }
355 
356 //***_plat__NVEnable()
357 // Enable NV memory.
358 //
359 // This version just pulls in data from a file. In a real TPM, with NV on chip,
360 // this function would verify the integrity of the saved context. If the NV
361 // memory was not on chip but was in something like RPMB, the NV state would be
362 // read in, decrypted and integrity checked.
363 //
364 // The recovery from an integrity failure depends on where the error occurred. It
365 // it was in the state that is discarded by TPM Reset, then the error is
366 // recoverable if the TPM is reset. Otherwise, the TPM must go into failure mode.
367 // return type: int
368 //      0           if success
369 //      > 0         if receive recoverable error
370 //      <0          if unrecoverable error
371 LIB_EXPORT int
_plat__NVEnable(void * platParameter)372 _plat__NVEnable(
373     void            *platParameter  // IN: platform specific parameters
374 	)
375 {
376     UNREFERENCED_PARAMETER(platParameter);
377 	DMSG("_plat__NVEnable()");
378 
379 
380     UINT32 retVal = 0;
381     UINT32 firmwareV1 = FIRMWARE_V1;
382     UINT32 firmwareV2 = FIRMWARE_V2;
383 
384     // Don't re-open the backing store.
385     if (s_NVInitialized) {
386         return 0;
387     }
388 
389 	// Clear NV
390     memset(s_NV, 0, NV_CHIP_MEMORY_SIZE);
391 
392     // Prepare for potential failure to retreieve NV from storage
393     s_chipRevision = ((((UINT64)firmwareV2) << 32) | (firmwareV1));
394     *(UINT64*)&(s_NV[NV_CHIP_REVISION_OFFSET]) = s_chipRevision;
395 
396     // Pick up our NV memory.
397     _plat__NvInitFromStorage();
398 
399     // Were we successful?
400     if (!s_NVInitialized) {
401         // Arriving here means one of two things: Either there existed no
402         // NV state before we came along and we just (re)initialized our
403         // storage. Or there is an error condition preventing us from
404         // accessing storage.  Check which is the case.
405         if (s_NVChipFileNeedsManufacture == FALSE) {
406             // This condition means we cannot access storage. However, it
407             // isn't up to the platform layer to decide what to do in this
408             // case. The decision to proceed is made in the fTPM init code
409             // in TA_CreateEntryPoint. Here, we're going to make sure that,
410             // should we decide not to just TEE_Panic, we can continue
411             // execution after (re)manufacture. Later an attempt at re-init
412             // can be made by calling _plat__NvInitFromStorage again.
413             retVal = 0;
414         }
415         else {
416             retVal = 1;
417         }
418 
419         // Going to manufacture, zero flags
420         g_chipFlags.flags = 0;
421 
422         // Save flags
423         _admin__SaveChipFlags();
424 
425         // Now we're done
426         s_NVInitialized = TRUE;
427 
428         return retVal;
429     }
430     else {
431         // In the transition out of UEFI to Windows, we may not tear down
432         // the TA. We close out one session and start another. This means
433         // our s_NVChipFileNeedsManufacture flag, if set, will be stale.
434         // Make sure we don't re-manufacture.
435         s_NVChipFileNeedsManufacture = FALSE;
436 
437         // We successfully initialized NV now pickup TPM state.
438         _admin__RestoreChipFlags();
439 
440 		// Success
441 		retVal = 1;
442     }
443 
444     return retVal;
445 }
446 
447 //***_plat__NVDisable()
448 // Disable NV memory
449 LIB_EXPORT void
_plat__NVDisable(void)450 _plat__NVDisable(
451     void
452     )
453 {
454 	UINT32 i;
455 
456     if (!s_NVInitialized) {
457         return;
458     }
459 
460 	// Final write
461     _plat__NvWriteBack();
462 
463 	// Close out all handles
464 	for (i = 0; i < NV_BLOCK_COUNT; i++) {
465 		if (IS_VALID(s_NVStore[i])) {
466 			TEE_CloseObject(s_NVStore[i]);
467 			s_NVStore[i] = TEE_HANDLE_NULL;
468 		}
469 	}
470 
471 	// We're no longer init-ed
472 	s_NVInitialized = FALSE;
473 
474     return;
475 }
476 
477 //***_plat__IsNvAvailable()
478 // Check if NV is available
479 // return type: int
480 //      0               NV is available
481 //      1               NV is not available due to write failure
482 //      2               NV is not available due to rate limit
483 LIB_EXPORT int
_plat__IsNvAvailable(void)484 _plat__IsNvAvailable(
485     void
486     )
487 {
488     // This is not enabled for OpTEE TA. Storage is always available.
489     return 0;
490 }
491 
492 
493 
494 //***_plat__NvMemoryRead()
495 // Function: Read a chunk of NV memory
496 LIB_EXPORT void
_plat__NvMemoryRead(unsigned int startOffset,unsigned int size,void * data)497 _plat__NvMemoryRead(
498     unsigned int     startOffset,   // IN: read start
499     unsigned int     size,          // IN: size of bytes to read
500     void            *data           // OUT: data buffer
501     )
502 {
503     pAssert((startOffset + size) <= NV_CHIP_MEMORY_SIZE);
504     pAssert(s_NV != NULL);
505 
506     memcpy(data, &s_NV[startOffset], size);
507 }
508 
509 //*** _plat__NvIsDifferent()
510 // This function checks to see if the NV is different from the test value. This is
511 // so that NV will not be written if it has not changed.
512 // return value: int
513 //  TRUE(1)    the NV location is different from the test value
514 //  FALSE(0)   the NV location is the same as the test value
515 LIB_EXPORT int
_plat__NvIsDifferent(unsigned int startOffset,unsigned int size,void * data)516 _plat__NvIsDifferent(
517     unsigned int     startOffset,   // IN: read start
518     unsigned int     size,          // IN: size of bytes to read
519     void            *data           // IN: data buffer
520     )
521 {
522     return (memcmp(&s_NV[startOffset], data, size) != 0);
523 }
524 
525 static
526 void
_plat__MarkDirtyBlocks(unsigned int startOffset,unsigned int size)527 _plat__MarkDirtyBlocks (
528 	unsigned int		startOffset,
529 	unsigned int		size
530 )
531 {
532 	unsigned int blockEnd;
533 	unsigned int blockStart;
534 	unsigned int i;
535 
536 	//
537 	// Integer math will round down to the start of the block.
538 	// blockEnd is actually the last block + 1.
539 	//
540 
541 	blockStart = startOffset / NV_BLOCK_SIZE;
542 	blockEnd = (startOffset + size) / NV_BLOCK_SIZE;
543 	if ((startOffset + size) % NV_BLOCK_SIZE != 0) {
544 		blockEnd += 1;
545 	}
546 
547 	for (i = blockStart; i < blockEnd; i++) {
548 		s_blockMap |= (0x1ULL << i);
549 	}
550 }
551 
552 //***_plat__NvMemoryWrite()
553 // This function is used to update NV memory. The "write" is to a memory copy of
554 // NV. At the end of the current command, any changes are written to
555 // the actual NV memory.
556 // NOTE: A useful optimization would be for this code to compare the current
557 // contents of NV with the local copy and note the blocks that have changed. Then
558 // only write those blocks when _plat__NvCommit() is called.
559 LIB_EXPORT int
_plat__NvMemoryWrite(unsigned int startOffset,unsigned int size,void * data)560 _plat__NvMemoryWrite(
561     unsigned int     startOffset,   // IN: write start
562     unsigned int     size,          // IN: size of bytes to write
563     void            *data           // OUT: data buffer
564     )
565 {
566     pAssert(startOffset + size <= NV_CHIP_MEMORY_SIZE);
567     pAssert(s_NV != NULL);
568 
569 	_plat__MarkDirtyBlocks(startOffset, size);
570     memcpy(&s_NV[startOffset], data, size);
571     return TRUE;
572 }
573 
574 //***_plat__NvMemoryClear()
575 // Function is used to set a range of NV memory bytes to an implementation-dependent
576 // value. The value represents the erase state of the memory.
577 LIB_EXPORT void
_plat__NvMemoryClear(unsigned int start,unsigned int size)578 _plat__NvMemoryClear(
579     unsigned int     start,         // IN: clear start
580     unsigned int     size           // IN: number of bytes to clear
581     )
582 {
583     pAssert(start + size <= NV_MEMORY_SIZE);
584 
585 	_plat__MarkDirtyBlocks(start, size);
586     memset(&s_NV[start], 0, size);
587 }
588 
589 //***_plat__NvMemoryMove()
590 // Function: Move a chunk of NV memory from source to destination
591 //      This function should ensure that if there overlap, the original data is
592 //      copied before it is written
593 LIB_EXPORT void
_plat__NvMemoryMove(unsigned int sourceOffset,unsigned int destOffset,unsigned int size)594 _plat__NvMemoryMove(
595     unsigned int     sourceOffset,  // IN: source offset
596     unsigned int     destOffset,    // IN: destination offset
597     unsigned int     size           // IN: size of data being moved
598     )
599 {
600     pAssert(sourceOffset + size <= NV_CHIP_MEMORY_SIZE);
601     pAssert(destOffset + size <= NV_CHIP_MEMORY_SIZE);
602     pAssert(s_NV != NULL);
603 
604 	_plat__MarkDirtyBlocks(sourceOffset, size);
605 	_plat__MarkDirtyBlocks(destOffset, size);
606 
607     memmove(&s_NV[destOffset], &s_NV[sourceOffset], size);
608 }
609 
610 //***_plat__NvCommit()
611 // This function writes the local copy of NV to NV for permanent store. It will write
612 // NV_MEMORY_SIZE bytes to NV. If a file is use, the entire file is written.
613 // return type: int
614 //  0       NV write success
615 //  non-0   NV write fail
616 LIB_EXPORT int
_plat__NvCommit(void)617 _plat__NvCommit(
618     void
619     )
620 {
621     _plat__NvWriteBack();
622     return 0;
623 }
624 
625 //***_plat__SetNvAvail()
626 // Set the current NV state to available.  This function is for testing purpose
627 // only.  It is not part of the platform NV logic
628 LIB_EXPORT void
_plat__SetNvAvail(void)629 _plat__SetNvAvail(
630     void
631     )
632 {
633     // NV will not be made unavailable on this platform
634     return;
635 }
636 
637 //***_plat__ClearNvAvail()
638 // Set the current NV state to unavailable.  This function is for testing purpose
639 // only.  It is not part of the platform NV logic
640 LIB_EXPORT void
_plat__ClearNvAvail(void)641 _plat__ClearNvAvail(
642     void
643     )
644 {
645     // The anti-set; not on this platform.
646     return;
647 }
648