From 1d6c7bb9773f76aa70ce65822fa001ff72892cd2 Mon Sep 17 00:00:00 2001 From: Vadim Bendebury Date: Thu, 28 Feb 2019 20:05:27 -0800 Subject: nvmem: test modifications to support the new scheme This patch includes changes to support testing of the new nvmem implementation. Making fizz compatible required duplicating a lot of functionality available in the test/ directory (fuzz/nvmem_tpm2_mock.c is very similar to test/nvmem_tpm2_mock.c), but I could not find an easy way to avoid it. BRANCH=cr50, cr50-mp BUG=b:69907320, b:129710256 CQ-DEPEND=CL:1496607 TEST=with the rest of the patches applied 'make buildall -j' succeeds, which confirms both test and fuzz success. Change-Id: Ife999b04d22f8ddbe9ea5d35f4c3e21f57592754 Signed-off-by: Vadim Bendebury Reviewed-on: https://chromium-review.googlesource.com/1450278 Reviewed-by: Andrey Pronin --- test/nvmem_tpm2_mock.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 test/nvmem_tpm2_mock.c (limited to 'test/nvmem_tpm2_mock.c') diff --git a/test/nvmem_tpm2_mock.c b/test/nvmem_tpm2_mock.c new file mode 100644 index 0000000000..070525406d --- /dev/null +++ b/test/nvmem_tpm2_mock.c @@ -0,0 +1,377 @@ +/* Copyright 2019 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +/* Stuff from tpm2 directory. */ + +#include "nvmem_test.h" + +#include "console.h" +#include "nvmem.h" +#include "util.h" + +#define NVMEM_CR50_SIZE 272 + +uint32_t s_evictNvStart; +uint32_t s_evictNvEnd; + +/* Calculate size of TPM NVMEM. */ +#define MOCK_NV_MEMORY_SIZE \ + (NVMEM_PARTITION_SIZE - sizeof(struct nvmem_tag) - NVMEM_CR50_SIZE) + +uint32_t nvmem_user_sizes[NVMEM_NUM_USERS] = {MOCK_NV_MEMORY_SIZE, + NVMEM_CR50_SIZE}; + +/* + * Sizes of the reserved objects stored in the TPM NVMEM. Note that the second + * last object is in fact a variable size field starting with 4 bytes of size + * and then up to 512 bytes of actual index data. The array below assumes that + * the full 512 bytes of the index space are used. + */ +const uint16_t res_sizes[] = {4, 2, 2, 2, 66, 66, 66, 66, 66, 66, + 34, 34, 34, 66, 66, 66, 8, 4, 134, 28, + 3, 4, 4, 4, 4, 4, 2, 15, 2, 8, + 4, 4, 4, 96, 2844, 424, 516, 8}; + +static uint16_t res_addrs[ARRAY_SIZE(res_sizes)]; + +BOOL NvEarlyStageFindHandle(TPM_HANDLE handle) +{ + size_t i; + + res_addrs[0] = 0; + + for (i = 1; i < ARRAY_SIZE(res_addrs); i++) + res_addrs[i] = res_addrs[i - 1] + res_sizes[i - 1]; + + s_evictNvStart = res_addrs[i - 1] + res_sizes[i - 1]; + + s_evictNvEnd = MOCK_NV_MEMORY_SIZE; + return 0; +} + +void NvGetReserved(UINT32 index, NV_RESERVED_ITEM *ri) +{ + uint32_t index_size; + + if (index >= ARRAY_SIZE(res_sizes)) { + ri->size = 0; + return; + } + + ri->offset = res_addrs[index]; + if (index != NV_RAM_INDEX_SPACE) { + ri->size = res_sizes[index]; + return; + } + + memcpy(&index_size, nvmem_cache_base(NVMEM_TPM) + ri->offset, + sizeof(index_size)); + + if (index_size == ~0) + /* Must be starting with empty flash memeory. */ + index_size = 0; + + ri->size = index_size + sizeof(index_size); +} + +UINT16 UINT16_Marshal(UINT16 *source, BYTE **buffer, INT32 *size) +{ + uint16_t value; + + if (!size || (*size < sizeof(value))) + return 0; + + value = htobe16(*source); + + memcpy(*buffer, &value, sizeof(value)); + *buffer += sizeof(value); + *size -= sizeof(value); + + return sizeof(value); +} + +UINT16 UINT32_Marshal(UINT32 *source, BYTE **buffer, INT32 *size) +{ + uint32_t value; + + if (!size || (*size < sizeof(value))) + return 0; + + value = htobe32(*source); + + memcpy(*buffer, &value, sizeof(value)); + *buffer += sizeof(value); + *size -= sizeof(value); + + return sizeof(value); +} + +UINT16 UINT64_Marshal(UINT64 *source, BYTE **buffer, INT32 *size) +{ + uint64_t value; + + if (!size || (*size < sizeof(value))) + return 0; + + value = htobe64(*source); + + memcpy(*buffer, &value, sizeof(value)); + *buffer += sizeof(value); + *size -= sizeof(value); + + return sizeof(value); +} + +UINT16 TPM2B_DIGEST_Marshal(TPM2B_DIGEST *source, BYTE **buffer, INT32 *size) +{ + UINT16 total_size; + INT32 i; + uint8_t *p; + + total_size = UINT16_Marshal(&source->t.size, buffer, size); + p = *buffer; + + for (i = 0; (i < source->t.size) && *size; ++i) { + *p++ = source->t.buffer[i]; + *size -= 1; + } + + total_size += i; + *buffer = p; + + return total_size; +} + +uint16_t TPM2B_AUTH_Marshal(TPM2B_AUTH *source, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Marshal(source, buffer, size); +} + +uint16_t TPM2B_NONCE_Marshal(TPM2B_AUTH *source, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Marshal(source, buffer, size); +} + +TPM_RC UINT16_Unmarshal(UINT16 *target, BYTE **buffer, INT32 *size) +{ + uint16_t value; + + if (!size || *size < sizeof(value)) + return TPM_RC_INSUFFICIENT; + + memcpy(&value, *buffer, sizeof(value)); + *target = be16toh(value); + + *buffer += sizeof(value); + *size -= sizeof(value); + + return TPM_RC_SUCCESS; +} + +TPM_RC UINT32_Unmarshal(UINT32 *target, BYTE **buffer, INT32 *size) +{ + uint32_t value; + + if (!size || *size < sizeof(value)) + return TPM_RC_INSUFFICIENT; + + memcpy(&value, *buffer, sizeof(value)); + *target = be32toh(value); + + *buffer += sizeof(value); + *size -= sizeof(value); + + return TPM_RC_SUCCESS; +} + +TPM_RC UINT64_Unmarshal(UINT64 *target, BYTE **buffer, INT32 *size) +{ + uint64_t value; + + if (!size || *size < sizeof(value)) + return TPM_RC_INSUFFICIENT; + + memcpy(&value, *buffer, sizeof(value)); + *target = be64toh(value); + + *buffer += sizeof(value); + *size -= sizeof(value); + + return TPM_RC_SUCCESS; +} + +TPM_RC TPM2B_DIGEST_Unmarshal(TPM2B_DIGEST *target, BYTE **buffer, INT32 *size) +{ + TPM_RC result; + INT32 i; + uint8_t *p; + + result = UINT16_Unmarshal(&target->t.size, buffer, size); + + if (result != TPM_RC_SUCCESS) + return result; + + if (target->t.size == 0) + return TPM_RC_SUCCESS; + + if ((target->t.size > sizeof(TPMU_HA)) || (target->t.size > *size)) + return TPM_RC_SIZE; + + p = *buffer; + for (i = 0; i < target->t.size; ++i) + target->t.buffer[i] = *p++; + + *buffer = p; + *size -= i; + + return TPM_RC_SUCCESS; +} + +TPM_RC TPM2B_AUTH_Unmarshal(TPM2B_AUTH *target, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Unmarshal(target, buffer, size); +} + +TPM_RC TPM2B_NONCE_Unmarshal(TPM2B_AUTH *target, BYTE **buffer, INT32 *size) +{ + return TPM2B_DIGEST_Unmarshal(target, buffer, size); +} + +#define ITER_INIT (~0) + +static void *get_cache_addr(size_t offset) +{ + return (void *)(((uintptr_t)nvmem_cache_base(NVMEM_TPM)) + offset); +} + +static void read_from_cache(size_t offset, size_t size, void *dest) +{ + nvmem_read(offset, size, dest, NVMEM_TPM); +} + +static void write_to_cache(size_t offset, size_t size, void *src) +{ + nvmem_write(offset, size, src, NVMEM_TPM); +} + +/* Copies of the appropriate functions from NV.c in TPM2 library. */ +static uint32_t nv_next(uint32_t *iter) +{ + uint32_t currentIter; + + if (*iter == ITER_INIT) + *iter = s_evictNvStart; + + if ((*iter + sizeof(uint32_t) > s_evictNvEnd) || !*iter) + return 0; + + currentIter = *iter; + read_from_cache(*iter, sizeof(uint32_t), iter); + if (!*iter || (*iter == ITER_INIT)) + return 0; + + return currentIter + sizeof(uint32_t); +} + +static uint32_t nv_get_end(void) +{ + uint32_t iter = ITER_INIT; + uint32_t endAddr = s_evictNvStart; + uint32_t currentAddr; + + while ((currentAddr = nv_next(&iter)) != 0) + endAddr = currentAddr; + + if (endAddr != s_evictNvStart) { + /* Read offset. */ + endAddr -= sizeof(uint32_t); + read_from_cache(endAddr, sizeof(uint32_t), &endAddr); + } + return endAddr; +} + +size_t add_evictable_obj(void *obj, size_t obj_size) +{ + uint32_t end_addr; + uint32_t next_addr; + uint32_t list_end = 0; + + end_addr = nv_get_end(); + + next_addr = end_addr + sizeof(uint32_t) + obj_size; + + if (next_addr >= s_evictNvEnd) { + ccprintf("%s: could not fit %d bytes!\n", __func__, obj_size); + return 0; + } + + /* Write next pointer */ + write_to_cache(end_addr, sizeof(uint32_t), &next_addr); + /* Write entity data. */ + write_to_cache(end_addr + sizeof(uint32_t), obj_size, obj); + + /* Write the end of list if it fits. */ + if (next_addr + sizeof(uint32_t) <= s_evictNvEnd) + write_to_cache(next_addr, sizeof(list_end), &list_end); + + return obj_size; +} + +/* + * It is the responsibility of the caller to pass the proper address of an + * object in the cache. + */ +void drop_evictable_obj(void *obj) +{ + uint32_t next_addr; + uint32_t list_end = 0; + uint32_t obj_addr; + + obj_addr = (uintptr_t)obj - (uintptr_t)nvmem_cache_base(NVMEM_TPM); + read_from_cache(obj_addr - sizeof(next_addr), sizeof(next_addr), + &next_addr); + ccprintf("%s:%d dropping obj at cache addr %x, offset %x, addr %p next " + "addr %x aka %x (off s_evictNvStart)\n", + __func__, __LINE__, obj_addr - s_evictNvStart, obj_addr, obj, + next_addr, next_addr - s_evictNvStart); + + /* + * Now, to make it easier to add objects behind the current one, let's + * pretend there is no more objects. + */ + write_to_cache(obj_addr - sizeof(next_addr), sizeof(list_end), + &list_end); + + if (!next_addr || (next_addr == s_evictNvEnd)) + return; + + /* + * Iterate over objects starting with next_addr, copying them into + * obj_addr. + */ + obj_addr = next_addr; + while (1) { + uint32_t next_next_addr; + uint32_t next_obj_size; + + read_from_cache(next_addr, sizeof(next_next_addr), + &next_next_addr); + + if (!next_next_addr || (next_next_addr == s_evictNvEnd)) + return; + + next_obj_size = next_next_addr - obj_addr - sizeof(uint32_t); + add_evictable_obj( + (void *)((uintptr_t)nvmem_cache_base(NVMEM_TPM) + + next_addr + sizeof(uint32_t)), + next_obj_size); + next_addr = next_next_addr; + obj_addr += next_obj_size + sizeof(next_obj_size); + } +} + +void *evictable_offs_to_addr(uint16_t offset) +{ + return (void *)((uintptr_t)get_cache_addr(s_evictNvStart) + offset); +} -- cgit v1.2.1