From c3b35a6b8537ed7f50ddf1f2721a2e2ca93b9108 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Wed, 6 Mar 2024 09:38:33 -0800 Subject: [PATCH 1/8] initial version --- linux-keystone-driver/keystone-ioctl.c | 7 +- sdk/include/host/Enclave.hpp | 19 +++ sdk/include/host/KeystoneDevice.hpp | 4 +- sdk/include/shared/keystone_user.h | 7 +- sdk/include/shared/sm_call.h | 32 ++++- sdk/src/host/Enclave.cpp | 189 +++++++++++++++++++------ sdk/src/host/KeystoneDevice.cpp | 9 +- sm/src/attest.c | 74 ++++++---- sm/src/enclave.c | 3 - sm/src/enclave.h | 1 + 10 files changed, 242 insertions(+), 103 deletions(-) diff --git a/linux-keystone-driver/keystone-ioctl.c b/linux-keystone-driver/keystone-ioctl.c index 08a50359a..9e2697117 100644 --- a/linux-keystone-driver/keystone-ioctl.c +++ b/linux-keystone-driver/keystone-ioctl.c @@ -56,6 +56,7 @@ int keystone_finalize_enclave(unsigned long arg) /* SBI Call */ create_args.epm_region.paddr = enclave->epm->pa; create_args.epm_region.size = enclave->epm->size; + create_args.free_paddr = enclave->free_paddr; utm = enclave->utm; @@ -67,12 +68,6 @@ int keystone_finalize_enclave(unsigned long arg) create_args.utm_region.size = 0; } - // physical addresses for runtime, user, and freemem - create_args.runtime_paddr = enclp->runtime_paddr; - create_args.user_paddr = enclp->user_paddr; - create_args.free_paddr = enclp->free_paddr; - create_args.free_requested = enclp->free_requested; - ret = sbi_sm_create_enclave(&create_args); if (ret.error) { diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index 57e571754..e951a1245 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -41,6 +41,7 @@ class Enclave { size_t shared_buffer_size; OcallFunc oFuncDispatch; bool mapUntrusted(size_t size); + void copyMem(uintptr_t dest_offset, uintptr_t src, size_t size); void copyFile(uintptr_t filePtr, size_t fileSize); void allocUninitialized(ElfFile* elfFile); void loadElf(ElfFile* elfFile); @@ -50,6 +51,19 @@ class Enclave { bool prepareEnclaveMemory(size_t requiredPages, uintptr_t alternatePhysAddr); bool initMemory(); + typedef struct { + char name[MSR_NAME_LEN]; + uintptr_t type; + std::string filepath; + } resource_info_t; + std::vector identityResident; + std::vector identityAbsent; + std::vector resident; + std::vector absent; + void* enclave_base = 0; + uintptr_t materializeResourceInfo(std::vector tempResidentResourcePtrs, + ElfFile* allElfFiles, std::vector resInfos); + public: Enclave(); ~Enclave(); @@ -66,6 +80,11 @@ class Enclave { uintptr_t alternatePhysAddr); Error destroy(); Error run(uintptr_t* ret = nullptr); + + // TODO(Evgeny): switch to errors. Currently, 0 = success, 1 = error. + uintptr_t addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity); + uintptr_t addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity); + void finalize(uintptr_t alternatePhysAddr = 0); }; uint64_t diff --git a/sdk/include/host/KeystoneDevice.hpp b/sdk/include/host/KeystoneDevice.hpp index d08d76d92..650b8cc8b 100644 --- a/sdk/include/host/KeystoneDevice.hpp +++ b/sdk/include/host/KeystoneDevice.hpp @@ -40,9 +40,7 @@ class KeystoneDevice { virtual bool initDevice(Params params); virtual Error create(uint64_t minPages); virtual uintptr_t initUTM(size_t size); - virtual Error finalize( - uintptr_t runtimePhysAddr, uintptr_t eappPhysAddr, uintptr_t freePhysAddr, - uintptr_t freeRequested); + virtual Error finalize(uintptr_t free_paddr); virtual Error destroy(); virtual Error run(uintptr_t* ret); virtual Error resume(uintptr_t* ret); diff --git a/sdk/include/shared/keystone_user.h b/sdk/include/shared/keystone_user.h index 585709cc9..160a91857 100644 --- a/sdk/include/shared/keystone_user.h +++ b/sdk/include/shared/keystone_user.h @@ -39,12 +39,7 @@ struct keystone_ioctl_create_enclave { // host -> driver uintptr_t min_pages; // create uintptr_t utm_size; // utm_init - - // host -> driver // finalize - uintptr_t runtime_paddr; - uintptr_t user_paddr; - uintptr_t free_paddr; - uintptr_t free_requested; + uintptr_t free_paddr; // finalize // driver -> host uintptr_t epm_paddr; diff --git a/sdk/include/shared/sm_call.h b/sdk/include/shared/sm_call.h index b9d8f959a..4769fd5ca 100644 --- a/sdk/include/shared/sm_call.h +++ b/sdk/include/shared/sm_call.h @@ -43,6 +43,7 @@ struct runtime_params_t { uintptr_t dram_base; uintptr_t dram_size; + uintptr_t loader_base; uintptr_t runtime_base; uintptr_t user_base; uintptr_t free_base; @@ -59,11 +60,34 @@ struct keystone_sbi_pregion_t { struct keystone_sbi_create_t { struct keystone_sbi_pregion_t epm_region; struct keystone_sbi_pregion_t utm_region; - - uintptr_t runtime_paddr; - uintptr_t user_paddr; uintptr_t free_paddr; - uintptr_t free_requested; }; +// TODO(Evgeny): how do we ensure no compiler re-ordering? +#define MSR_NAME_LEN 64 +typedef struct { + char name[MSR_NAME_LEN]; + uintptr_t type; + char hash[MDSIZE]; +} resource_hash_t; + +typedef struct { + char name[MSR_NAME_LEN]; + uintptr_t type; + uintptr_t offset; + uintptr_t size; +} resource_ptr_t; + +// TODO(Evgeny): a way to make this more convenient? should I make the pointers typed? +typedef struct { + uintptr_t runtime_arr, id_res_arr, + id_abs_arr, res_arr, abs_arr, data; + // resource_value_t runtime_values[]; + // resource_ptr_t identity_resident[]; + // resource_hash_t identity_absent[]; + // resource_ptr_t resident[]; + // resource_hash_t absent[]; + // byte data[]; +} enclave_bundle_header_t; + #endif // __SM_CALL_H__ diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index 8316a9da9..cabb8c7f4 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -23,12 +23,12 @@ Enclave::~Enclave() { } uint64_t -calculate_required_pages(ElfFile** elfFiles, size_t numElfFiles) { +calculate_required_pages(ElfFile* elfFiles, size_t numElfFiles) { uint64_t req_pages = 0; for (int i = 0; i < numElfFiles; i++) { - ElfFile* elfFile = elfFiles[i]; - req_pages += ceil(elfFile->getFileSize() / PAGE_SIZE); + ElfFile& elfFile = elfFiles[i]; + req_pages += ceil(elfFile.getFileSize() / PAGE_SIZE); } /* FIXME: calculate the required number of pages for the page table. * We actually don't know how many page tables the enclave might need, @@ -74,6 +74,18 @@ Enclave::prepareEnclaveMemory(size_t requiredPages, uintptr_t alternatePhysAddr) return true; } +void +Enclave::copyMem(uintptr_t dest_offset, uintptr_t src, size_t size) { + size_t bytesRemaining = size; + while (bytesRemaining > 0) { + size_t bytesToWrite = (bytesRemaining > PAGE_SIZE) ? PAGE_SIZE : bytesRemaining; + pMemory->writeMem(src, dest_offset, bytesToWrite); + src += bytesToWrite; + dest_offset += bytesToWrite; + bytesRemaining -= bytesToWrite; + } +} + void Enclave::copyFile(uintptr_t filePtr, size_t fileSize) { uintptr_t startOffset = pMemory->getCurrentOffset(); @@ -142,71 +154,158 @@ Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, cons return Error::Success; } -Error -Enclave::init(const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params) { - return this->init(eapppath, runtimepath, loaderpath, _params, (uintptr_t)0); +// TODO(Evgeny): switch to errors. Currently, 0 = success, 1 = error. +uintptr_t +Enclave::addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity) { + if (strlen(name) >= MSR_NAME_LEN) { + return 1; + } + resource_info_t* resInfo = 0; + if (identity) { + identityResident.push_back({}); + resInfo = &identityResident.back(); + } else { + resident.push_back({}); + resInfo = &resident.back(); + } + strcpy(resInfo->name, name); + resInfo->type = type; + resInfo->filepath = std::string(filepath); + return 0; } -Error -Enclave::init( - const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params, - uintptr_t alternatePhysAddr) { - params = _params; - - pMemory = new PhysicalEnclaveMemory(); - pDevice = new KeystoneDevice(); - - ElfFile* enclaveFile = new ElfFile(eapppath); - ElfFile* runtimeFile = new ElfFile(runtimepath); - ElfFile* loaderFile = new ElfFile(loaderpath); +uintptr_t +Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity) { + if (strlen(name) >= MSR_NAME_LEN) { + return 1; + } + resource_hash_t* resHash = 0; + if (identity) { + identityAbsent.push_back({}); + resHash = &identityAbsent.back(); + } else { + absent.push_back({}); + resHash = &absent.back(); + } + strcpy(resHash->name, name); + resHash->type = type; + memcpy(resHash->hash, hash, MDSIZE); + return 0; +} - if (!pDevice->initDevice(params)) { - destroy(); - return Error::DeviceInitFailure; +uintptr_t +Enclave::materializeResourceInfo(std::vector tempResidentResourcePtrs, ElfFile* elfFiles, + std::vector resInfos) { + for (uintptr_t i = 0; i < resInfos.size(); i++) { + const resource_info_t& resInfo = resInfos[i]; + ElfFile& elfFile = elfFiles[i]; + tempResidentResourcePtrs.push_back({0}); + resource_ptr_t& tempResourcePtr = tempResidentResourcePtrs.back(); + strcpy(tempResourcePtr.name, resInfo.name); + tempResourcePtr.type = resInfo.type; + tempResourcePtr.offset = pMemory->getCurrentOffset(); + tempResourcePtr.size = (uintptr_t) elfFile.getFileSize(); + copyFile((uintptr_t) elfFile.getPtr(), elfFile.getFileSize()); // TODO(Evgeny): incorporate cur into inside } + return 0; +} - ElfFile* elfFiles[3] = {enclaveFile, runtimeFile, loaderFile}; - size_t requiredPages = calculate_required_pages(elfFiles, 3); +uintptr_t +Enclave::finalize(uintptr_t alternatePhysAddr = 0) { + // TODO(Evgeny): ensure this is not called twice, no adds after, etc. + // TODO(Evgeny): how is alternatePhysAddr useful? + // allocate enclave memory + std::vector allElfFiles; + for (const resource_info_t& res_info : identityResident) { + allElfFiles.push_back(ElfFile(res_info.filepath)); + } + for (const resource_info_t& res_info : resident) { + allElfFiles.push_back(ElfFile(res_info.filepath)); + } + size_t requiredPages = calculate_required_pages(&allElfFiles[0], allElfFiles.size()); if (!prepareEnclaveMemory(requiredPages, alternatePhysAddr)) { destroy(); - return Error::DeviceError; + return 1; + // return Error::DeviceError; } if (!pMemory->allocUtm(params.getUntrustedSize())) { ERROR("failed to init untrusted memory - ioctl() failed"); destroy(); - return Error::DeviceError; + return 1; + // return Error::DeviceError; } - - /* Copy loader into beginning of enclave memory */ - copyFile((uintptr_t) loaderFile->getPtr(), loaderFile->getFileSize()); - - pMemory->startRuntimeMem(); - copyFile((uintptr_t) runtimeFile->getPtr(), runtimeFile->getFileSize()); - pMemory->startEappMem(); - copyFile((uintptr_t) enclaveFile->getPtr(), enclaveFile->getFileSize()); - - pMemory->startFreeMem(); - - if (pDevice->finalize( - pMemory->getRuntimePhysAddr(), pMemory->getEappPhysAddr(), - pMemory->getFreePhysAddr(), params.getFreeMemSize()) != Error::Success) { + enclave_bundle_header_t ebundle_h; + + // space out the arrays + ebundle_h.runtime_arr = (uintptr_t) sizeof(enclave_bundle_header_t); + ebundle_h.id_res_arr = ebundle_h.runtime_arr + 0; // TODO(Evgeny) + ebundle_h.id_abs_arr = ebundle_h.id_res_arr + + (uintptr_t) (sizeof(resource_ptr_t) * identityResident.size()); + ebundle_h.res_arr = ebundle_h.id_abs_arr + + (uintptr_t) (sizeof(resource_hash_t) * identityAbsent.size()); + ebundle_h.abs_arr = ebundle_h.res_arr + + (uintptr_t) (sizeof(resource_ptr_t) * resident.size()); + ebundle_h.data = ebundle_h.abs_arr + + (uintptr_t) (sizeof(resource_hash_t) * absent.size()); + + copyMem(0, (uintptr_t) &ebundle_h, sizeof(ebundle_h)); + + // fill in the arrays & data + // TODO(Evgeny): runtime values + copyMem(ebundle_h.id_abs_arr, (uintptr_t) &identityAbsent[0], sizeof(resource_hash_t) * identityAbsent.size()); + copyMem(ebundle_h.abs_arr, (uintptr_t) &absent[0], sizeof(resource_hash_t) * absent.size()); + std::vector tempIdentityResidentResourcePtrs; + materializeResourceInfo(tempIdentityResidentResourcePtrs, &allElfFiles[0], identityResident); + copyMem(ebundle_h.id_res_arr, (uintptr_t) &tempIdentityResidentResourcePtrs[0], sizeof(resource_hash_t) * tempIdentityResidentResourcePtrs.size()); + std::vector tempResidentResourcePtrs; + materializeResourceInfo(tempResidentResourcePtrs, &allElfFiles[identityResident.size()], resident); + copyMem(ebundle_h.res_arr, (uintptr_t) &tempResidentResourcePtrs[0], sizeof(resource_hash_t) * tempResidentResourcePtrs.size()); + + if (pDevice->finalize(pMemory->getCurrentEPMAddress()) != Error::Success) { destroy(); - return Error::DeviceError; + return 1; + // return Error::DeviceError; } if (!mapUntrusted(params.getUntrustedSize())) { ERROR( "failed to finalize enclave - cannot obtain the untrusted buffer " "pointer \n"); destroy(); - return Error::DeviceMemoryMapError; + return 1; + // return Error::DeviceMemoryMapError; } - /* ELF files are no longer needed */ - delete enclaveFile; - delete runtimeFile; - delete loaderFile; + // TODO(Evgeny): validate that loader, runtime, and eapp are present + return 0; +} + +Error +Enclave::init(const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params) { + return this->init(eapppath, runtimepath, loaderpath, _params, (uintptr_t)0); +} + +Error +Enclave::init( + const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params, + uintptr_t alternatePhysAddr) { + params = _params; + + pMemory = new PhysicalEnclaveMemory(); + pDevice = new KeystoneDevice(); + + if (!pDevice->initDevice(params)) { + destroy(); + return Error::DeviceInitFailure; + } + + // TODO(Evgeny): errors + addResidentResource("eapp", 0, eapppath, true); + addResidentResource("runtime", 0, runtimepath, true); + addResidentResource("loader", 0, loaderpath, true); + finalize(); + return Error::Success; } diff --git a/sdk/src/host/KeystoneDevice.cpp b/sdk/src/host/KeystoneDevice.cpp index 42e8d4c4c..d05140408 100644 --- a/sdk/src/host/KeystoneDevice.cpp +++ b/sdk/src/host/KeystoneDevice.cpp @@ -39,15 +39,10 @@ KeystoneDevice::initUTM(size_t size) { } Error -KeystoneDevice::finalize( - uintptr_t runtimePhysAddr, uintptr_t eappPhysAddr, uintptr_t freePhysAddr, - uintptr_t freeRequested) { +KeystoneDevice::finalize(uintptr_t free_paddr) { struct keystone_ioctl_create_enclave encl; encl.eid = eid; - encl.runtime_paddr = runtimePhysAddr; - encl.user_paddr = eappPhysAddr; - encl.free_paddr = freePhysAddr; - encl.free_requested = freeRequested; + encl.free_paddr = free_paddr; if (ioctl(fd, KEYSTONE_IOC_FINALIZE_ENCLAVE, &encl)) { perror("ioctl error"); diff --git a/sm/src/attest.c b/sm/src/attest.c index cdef976da..9dcd87519 100644 --- a/sm/src/attest.c +++ b/sm/src/attest.c @@ -7,45 +7,61 @@ #include "page.h" #include -/* This will hash the loader and the runtime + eapp elf files. */ -static int validate_and_hash_epm(hash_ctx* ctx, struct enclave* encl) -{ - uintptr_t loader = encl->params.dram_base; // also base - uintptr_t runtime = encl->params.runtime_base; - uintptr_t eapp = encl->params.user_base; - uintptr_t free = encl->params.free_base; - - // ensure pointers don't point to middle of correct files - uintptr_t sizes[3] = {runtime - loader, eapp - runtime, free - eapp}; - hash_extend(ctx, (void*) sizes, sizeof(sizes)); - - // using pointers to ensure that they themselves are correct - // TODO(Evgeny): can extend by entire file instead of page at a time? - for (uintptr_t page = loader; page < runtime; page += RISCV_PGSIZE) { - hash_extend_page(ctx, (void*) page); - } - for (uintptr_t page = runtime; page < eapp; page += RISCV_PGSIZE) { - hash_extend_page(ctx, (void*) page); - } - for (uintptr_t page = eapp; page < free; page += RISCV_PGSIZE) { - hash_extend_page(ctx, (void*) page); +int measure_res_arr(resource_hash_t* elem, resource_hash_t* end, hash_ctx* hash_ctx) { + for (; elem < end; elem++) { + hash_extend(hash_ctx, elem, sizeof(elem[0])); } return 0; } +int measure_res_arr(resource_ptr_t* elem, resource_ptr_t* end, hash_ctx* hash_ctx, void* limit) { + for (; elem < end; elem++) { + hash_extend(hash_ctx, elem->name, sizeof(elem->name)); + hash_extend(hash_ctx, elem->type, sizeof(elem->type)); + if (elem->offset + elem->size >= limit) { + return 1; + } + hash_extend(hash_ctx, (void*) elem->offset, elem->size); // TODO: is > page ok? + } + return 0; +} + unsigned long validate_and_hash_enclave(struct enclave* enclave){ - hash_ctx ctx; - hash_init(&ctx); + // TODO(Evgeny): move discovery into enclave + uintptr_t ebase = enclave->params.dram_base; + enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) ebase; + for (resource_ptr_t* id_res_resource = ebundle_h->id_res_arr; id_res_resource < ebundle_h->id_abs_arr; id_res_resource++) { + if (strcmp(id_res_resource->name, "loader") == 0) { + enclave->params.loader_base = ebase + id_res_resource->offset; + } + if (strcmp(id_res_resource->name, "runtime") == 0) { + enclave->params.runtime_base = ebase + id_res_resource->offset; + } + if (strcmp(id_res_resource->name, "eapp") == 0) { + enclave->params.user_base = ebase + id_res_resource->offset; + } + } + if (!enclave->params.loader_base || !enclave->params.runtime_base || !enclave->params.user_base) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; + } + void* free = (void *) enclave->params.free_base; // TODO: ensure untrusted and free sizes // hash the epm contents - int valid = validate_and_hash_epm(&ctx, enclave); - - if(valid == -1){ - return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; + hash_ctx ctx; + hash_init(&ctx); + bool fail_state = 0; + // fail_state |= measure_res_arr((void *) ebase + ebundle_h->runtime_arr, (void *) ebase + ebundle_h->id_res_arr, &ctx); + fail_state |= measure_res_arr(ebase + ebundle_h->id_res_arr, ebase + ebundle_h->id_abs_arr, &ctx, free); + fail_state |= measure_res_arr(ebase + ebundle_h->id_abs_arr, ebase + ebundle_h->res_arr, &ctx); + hash_ctx ctx_copy = ctx; + hash_finalize(enclave->identity, &ctx_copy); + fail_state |= measure_res_arr(ebase + ebundle_h->res_arr, ebase + ebundle_h->abs_arr, &ctx, free); + fail_state |= measure_res_arr(ebase + ebundle_h->abs_arr, ebase + ebundle_h->data, &ctx); + if (fail_state) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; } - hash_finalize(enclave->hash, &ctx); return SBI_ERR_SM_ENCLAVE_SUCCESS; diff --git a/sm/src/enclave.c b/sm/src/enclave.c index 35e423889..ff1bb4af4 100644 --- a/sm/src/enclave.c +++ b/sm/src/enclave.c @@ -355,12 +355,9 @@ unsigned long create_enclave(unsigned long *eidptr, struct keystone_sbi_create_t struct runtime_params_t params; params.dram_base = base; params.dram_size = size; - params.runtime_base = create_args.runtime_paddr; - params.user_base = create_args.user_paddr; params.free_base = create_args.free_paddr; params.untrusted_base = utbase; params.untrusted_size = utsize; - params.free_requested = create_args.free_requested; // allocate eid diff --git a/sm/src/enclave.h b/sm/src/enclave.h index 0399a4d3d..09024d0ee 100644 --- a/sm/src/enclave.h +++ b/sm/src/enclave.h @@ -64,6 +64,7 @@ struct enclave struct enclave_region regions[ENCLAVE_REGIONS_MAX]; /* measurement */ + byte identity[MDSIZE]; byte hash[MDSIZE]; byte sign[SIGNATURE_SIZE]; From cbb953e03f02f28577da37e18426afb5340b8e33 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Fri, 22 Mar 2024 14:09:29 -0700 Subject: [PATCH 2/8] [undo me] works minus expected hash --- linux-keystone-driver/keystone-ioctl.c | 4 +- linux-keystone-driver/keystone.c | 8 +- sdk/include/host/Enclave.hpp | 7 +- sdk/include/host/KeystoneDevice.hpp | 2 +- sdk/include/host/Memory.hpp | 1 + sdk/include/shared/keystone_user.h | 2 +- sdk/include/shared/sm_call.h | 9 +- sdk/src/host/Enclave.cpp | 103 +++++++++------------ sdk/src/host/KeystoneDevice.cpp | 4 +- sdk/src/host/PhysicalEnclaveMemory.cpp | 5 +- sm/src/attest.c | 123 ++++++++++++++++++------- sm/src/enclave.c | 29 ++---- 12 files changed, 168 insertions(+), 129 deletions(-) diff --git a/linux-keystone-driver/keystone-ioctl.c b/linux-keystone-driver/keystone-ioctl.c index 9e2697117..9b88b37fc 100644 --- a/linux-keystone-driver/keystone-ioctl.c +++ b/linux-keystone-driver/keystone-ioctl.c @@ -56,7 +56,7 @@ int keystone_finalize_enclave(unsigned long arg) /* SBI Call */ create_args.epm_region.paddr = enclave->epm->pa; create_args.epm_region.size = enclave->epm->size; - create_args.free_paddr = enclave->free_paddr; + create_args.free_offset = enclp->free_offset; utm = enclave->utm; @@ -71,7 +71,7 @@ int keystone_finalize_enclave(unsigned long arg) ret = sbi_sm_create_enclave(&create_args); if (ret.error) { - keystone_err("keystone_create_enclave: SBI call failed with error code %ld\n", ret.error); + keystone_err("keystone_finalize_enclave: SBI create call failed with error code %ld\n", ret.error); goto error_destroy_enclave; } diff --git a/linux-keystone-driver/keystone.c b/linux-keystone-driver/keystone.c index 4486dfb76..1330fcd16 100644 --- a/linux-keystone-driver/keystone.c +++ b/linux-keystone-driver/keystone.c @@ -41,7 +41,7 @@ int keystone_mmap(struct file* filp, struct vm_area_struct *vma) struct utm* utm; struct epm* epm; struct enclave* enclave; - unsigned long vsize, psize; + unsigned long vsize, psize, offset; vaddr_t paddr; enclave = get_enclave_by_id((unsigned long) filp->private_data); if(!enclave) { @@ -54,9 +54,11 @@ int keystone_mmap(struct file* filp, struct vm_area_struct *vma) vsize = vma->vm_end - vma->vm_start; if(enclave->is_init){ - if (vsize > PAGE_SIZE) + psize = epm->size; + offset = vma->vm_pgoff << PAGE_SHIFT; + if (offset >= psize || vsize + offset > psize) return -EINVAL; - paddr = epm->pa + (vma->vm_pgoff << PAGE_SHIFT); + paddr = epm->pa + offset; remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT, diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index e951a1245..ee93e33c6 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "./common.h" extern "C" { @@ -61,8 +62,8 @@ class Enclave { std::vector resident; std::vector absent; void* enclave_base = 0; - uintptr_t materializeResourceInfo(std::vector tempResidentResourcePtrs, - ElfFile* allElfFiles, std::vector resInfos); + uintptr_t materializeResourceInfo(resource_ptr_t* residentResPtrs, + ElfFile** allElfFiles, std::vector resInfos); public: Enclave(); @@ -84,7 +85,7 @@ class Enclave { // TODO(Evgeny): switch to errors. Currently, 0 = success, 1 = error. uintptr_t addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity); uintptr_t addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity); - void finalize(uintptr_t alternatePhysAddr = 0); + uintptr_t finalize(uintptr_t alternatePhysAddr = 0); }; uint64_t diff --git a/sdk/include/host/KeystoneDevice.hpp b/sdk/include/host/KeystoneDevice.hpp index 650b8cc8b..3833ce890 100644 --- a/sdk/include/host/KeystoneDevice.hpp +++ b/sdk/include/host/KeystoneDevice.hpp @@ -40,7 +40,7 @@ class KeystoneDevice { virtual bool initDevice(Params params); virtual Error create(uint64_t minPages); virtual uintptr_t initUTM(size_t size); - virtual Error finalize(uintptr_t free_paddr); + virtual Error finalize(uintptr_t free_offset); virtual Error destroy(); virtual Error run(uintptr_t* ret); virtual Error resume(uintptr_t* ret); diff --git a/sdk/include/host/Memory.hpp b/sdk/include/host/Memory.hpp index 203c82ed3..f5e290949 100644 --- a/sdk/include/host/Memory.hpp +++ b/sdk/include/host/Memory.hpp @@ -54,6 +54,7 @@ class Memory { size_t epmSize; uintptr_t epmFreeList; uintptr_t startAddr; + uintptr_t vaStartAddr; // Keystone Device runtime params uintptr_t runtimePhysAddr; diff --git a/sdk/include/shared/keystone_user.h b/sdk/include/shared/keystone_user.h index 160a91857..a4cbb9b31 100644 --- a/sdk/include/shared/keystone_user.h +++ b/sdk/include/shared/keystone_user.h @@ -39,7 +39,7 @@ struct keystone_ioctl_create_enclave { // host -> driver uintptr_t min_pages; // create uintptr_t utm_size; // utm_init - uintptr_t free_paddr; // finalize + uintptr_t free_offset; // finalize // driver -> host uintptr_t epm_paddr; diff --git a/sdk/include/shared/sm_call.h b/sdk/include/shared/sm_call.h index 4769fd5ca..7e793a16d 100644 --- a/sdk/include/shared/sm_call.h +++ b/sdk/include/shared/sm_call.h @@ -60,11 +60,13 @@ struct keystone_sbi_pregion_t { struct keystone_sbi_create_t { struct keystone_sbi_pregion_t epm_region; struct keystone_sbi_pregion_t utm_region; - uintptr_t free_paddr; + uintptr_t free_offset; }; // TODO(Evgeny): how do we ensure no compiler re-ordering? #define MSR_NAME_LEN 64 +// #include "../common/sha3.h" // TODO(Evgeny): fix the include +#define MDSIZE 64 typedef struct { char name[MSR_NAME_LEN]; uintptr_t type; @@ -78,6 +80,11 @@ typedef struct { uintptr_t size; } resource_ptr_t; +typedef struct { + char name[MSR_NAME_LEN]; + uintptr_t val; +} runtime_val_t; + // TODO(Evgeny): a way to make this more convenient? should I make the pointers typed? typedef struct { uintptr_t runtime_arr, id_res_arr, diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index cabb8c7f4..edd04248a 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -23,12 +23,12 @@ Enclave::~Enclave() { } uint64_t -calculate_required_pages(ElfFile* elfFiles, size_t numElfFiles) { +calculate_required_pages(ElfFile** elfFiles, size_t numElfFiles) { uint64_t req_pages = 0; for (int i = 0; i < numElfFiles; i++) { - ElfFile& elfFile = elfFiles[i]; - req_pages += ceil(elfFile.getFileSize() / PAGE_SIZE); + ElfFile* elfFile = elfFiles[i]; + req_pages += ceil(elfFile->getFileSize() / PAGE_SIZE); } /* FIXME: calculate the required number of pages for the page table. * We actually don't know how many page tables the enclave might need, @@ -74,18 +74,6 @@ Enclave::prepareEnclaveMemory(size_t requiredPages, uintptr_t alternatePhysAddr) return true; } -void -Enclave::copyMem(uintptr_t dest_offset, uintptr_t src, size_t size) { - size_t bytesRemaining = size; - while (bytesRemaining > 0) { - size_t bytesToWrite = (bytesRemaining > PAGE_SIZE) ? PAGE_SIZE : bytesRemaining; - pMemory->writeMem(src, dest_offset, bytesToWrite); - src += bytesToWrite; - dest_offset += bytesToWrite; - bytesRemaining -= bytesToWrite; - } -} - void Enclave::copyFile(uintptr_t filePtr, size_t fileSize) { uintptr_t startOffset = pMemory->getCurrentOffset(); @@ -194,34 +182,42 @@ Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, b } uintptr_t -Enclave::materializeResourceInfo(std::vector tempResidentResourcePtrs, ElfFile* elfFiles, +Enclave::materializeResourceInfo(resource_ptr_t* residentResPtrs, ElfFile** elfFiles, std::vector resInfos) { for (uintptr_t i = 0; i < resInfos.size(); i++) { const resource_info_t& resInfo = resInfos[i]; - ElfFile& elfFile = elfFiles[i]; - tempResidentResourcePtrs.push_back({0}); - resource_ptr_t& tempResourcePtr = tempResidentResourcePtrs.back(); - strcpy(tempResourcePtr.name, resInfo.name); - tempResourcePtr.type = resInfo.type; - tempResourcePtr.offset = pMemory->getCurrentOffset(); - tempResourcePtr.size = (uintptr_t) elfFile.getFileSize(); - copyFile((uintptr_t) elfFile.getPtr(), elfFile.getFileSize()); // TODO(Evgeny): incorporate cur into inside + ElfFile* elfFile = elfFiles[i]; + resource_ptr_t* resPtr = residentResPtrs + i; + strcpy(resPtr->name, resInfo.name); + resPtr->type = resInfo.type; + resPtr->offset = pMemory->getCurrentOffset(); + resPtr->size = (uintptr_t) elfFile->getFileSize(); + copyFile((uintptr_t) elfFile->getPtr(), elfFile->getFileSize()); } return 0; } uintptr_t -Enclave::finalize(uintptr_t alternatePhysAddr = 0) { +Enclave::finalize(uintptr_t alternatePhysAddr) { // TODO(Evgeny): ensure this is not called twice, no adds after, etc. // TODO(Evgeny): how is alternatePhysAddr useful? + + pMemory = new PhysicalEnclaveMemory(); + pDevice = new KeystoneDevice(); + + if (!pDevice->initDevice(params)) { + destroy(); + return 1; + // return Error::DeviceInitFailure; + } // allocate enclave memory - std::vector allElfFiles; + std::vector allElfFiles; for (const resource_info_t& res_info : identityResident) { - allElfFiles.push_back(ElfFile(res_info.filepath)); + allElfFiles.push_back(new ElfFile(res_info.filepath)); } for (const resource_info_t& res_info : resident) { - allElfFiles.push_back(ElfFile(res_info.filepath)); + allElfFiles.push_back(new ElfFile(res_info.filepath)); } size_t requiredPages = calculate_required_pages(&allElfFiles[0], allElfFiles.size()); if (!prepareEnclaveMemory(requiredPages, alternatePhysAddr)) { @@ -236,34 +232,33 @@ Enclave::finalize(uintptr_t alternatePhysAddr = 0) { // return Error::DeviceError; } - enclave_bundle_header_t ebundle_h; + uintptr_t va_epm = pMemory->vaStartAddr; + enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) va_epm; // space out the arrays - ebundle_h.runtime_arr = (uintptr_t) sizeof(enclave_bundle_header_t); - ebundle_h.id_res_arr = ebundle_h.runtime_arr + 0; // TODO(Evgeny) - ebundle_h.id_abs_arr = ebundle_h.id_res_arr + ebundle_h->runtime_arr = (uintptr_t) sizeof(enclave_bundle_header_t); + ebundle_h->id_res_arr = ebundle_h->runtime_arr + 0; // TODO(Evgeny) + ebundle_h->id_abs_arr = ebundle_h->id_res_arr + (uintptr_t) (sizeof(resource_ptr_t) * identityResident.size()); - ebundle_h.res_arr = ebundle_h.id_abs_arr + ebundle_h->res_arr = ebundle_h->id_abs_arr + (uintptr_t) (sizeof(resource_hash_t) * identityAbsent.size()); - ebundle_h.abs_arr = ebundle_h.res_arr + ebundle_h->abs_arr = ebundle_h->res_arr + (uintptr_t) (sizeof(resource_ptr_t) * resident.size()); - ebundle_h.data = ebundle_h.abs_arr + ebundle_h->data = ebundle_h->abs_arr + (uintptr_t) (sizeof(resource_hash_t) * absent.size()); - - copyMem(0, (uintptr_t) &ebundle_h, sizeof(ebundle_h)); + pMemory->epmFreeList = ROUND_UP(ebundle_h->data, PAGE_BITS); // fill in the arrays & data // TODO(Evgeny): runtime values - copyMem(ebundle_h.id_abs_arr, (uintptr_t) &identityAbsent[0], sizeof(resource_hash_t) * identityAbsent.size()); - copyMem(ebundle_h.abs_arr, (uintptr_t) &absent[0], sizeof(resource_hash_t) * absent.size()); - std::vector tempIdentityResidentResourcePtrs; - materializeResourceInfo(tempIdentityResidentResourcePtrs, &allElfFiles[0], identityResident); - copyMem(ebundle_h.id_res_arr, (uintptr_t) &tempIdentityResidentResourcePtrs[0], sizeof(resource_hash_t) * tempIdentityResidentResourcePtrs.size()); - std::vector tempResidentResourcePtrs; - materializeResourceInfo(tempResidentResourcePtrs, &allElfFiles[identityResident.size()], resident); - copyMem(ebundle_h.res_arr, (uintptr_t) &tempResidentResourcePtrs[0], sizeof(resource_hash_t) * tempResidentResourcePtrs.size()); - - if (pDevice->finalize(pMemory->getCurrentEPMAddress()) != Error::Success) { + memcpy((void*) (va_epm + ebundle_h->id_abs_arr), &identityAbsent[0], sizeof(resource_hash_t) * identityAbsent.size()); + memcpy((void*) (va_epm + ebundle_h->abs_arr), &absent[0], sizeof(resource_hash_t) * absent.size()); + materializeResourceInfo((resource_ptr_t*) (va_epm + ebundle_h->id_res_arr), &allElfFiles[0], identityResident); + // copyFile((uintptr_t) &tempIdentityResidentResourcePtrs[0], sizeof(resource_hash_t) * tempIdentityResidentResourcePtrs.size()); + // std::vector tempResidentResourcePtrs; + // materializeResourceInfo(tempResidentResourcePtrs, &allElfFiles[identityResident.size()], resident); + // copyFile((uintptr_t) &tempResidentResourcePtrs[0], sizeof(resource_hash_t) * tempResidentResourcePtrs.size()); + + if (pDevice->finalize(pMemory->getCurrentOffset()) != Error::Success) { destroy(); return 1; // return Error::DeviceError; @@ -292,19 +287,11 @@ Enclave::init( uintptr_t alternatePhysAddr) { params = _params; - pMemory = new PhysicalEnclaveMemory(); - pDevice = new KeystoneDevice(); - - if (!pDevice->initDevice(params)) { - destroy(); - return Error::DeviceInitFailure; - } - // TODO(Evgeny): errors - addResidentResource("eapp", 0, eapppath, true); - addResidentResource("runtime", 0, runtimepath, true); addResidentResource("loader", 0, loaderpath, true); - finalize(); + addResidentResource("runtime", 0, runtimepath, true); + addResidentResource("eapp", 0, eapppath, true); + finalize(alternatePhysAddr); return Error::Success; } diff --git a/sdk/src/host/KeystoneDevice.cpp b/sdk/src/host/KeystoneDevice.cpp index d05140408..f5ccb74a3 100644 --- a/sdk/src/host/KeystoneDevice.cpp +++ b/sdk/src/host/KeystoneDevice.cpp @@ -39,10 +39,10 @@ KeystoneDevice::initUTM(size_t size) { } Error -KeystoneDevice::finalize(uintptr_t free_paddr) { +KeystoneDevice::finalize(uintptr_t free_offset) { struct keystone_ioctl_create_enclave encl; encl.eid = eid; - encl.free_paddr = free_paddr; + encl.free_offset = free_offset; if (ioctl(fd, KEYSTONE_IOC_FINALIZE_ENCLAVE, &encl)) { perror("ioctl error"); diff --git a/sdk/src/host/PhysicalEnclaveMemory.cpp b/sdk/src/host/PhysicalEnclaveMemory.cpp index ed95d8674..402404ea0 100644 --- a/sdk/src/host/PhysicalEnclaveMemory.cpp +++ b/sdk/src/host/PhysicalEnclaveMemory.cpp @@ -10,10 +10,12 @@ void PhysicalEnclaveMemory::init( KeystoneDevice* dev, uintptr_t phys_addr, size_t min_pages) { pDevice = dev; + assert(pDevice); // TODO(dayeol): need to set actual EPM size epmSize = PAGE_SIZE * min_pages; epmFreeList = 0; startAddr = phys_addr; + vaStartAddr = reinterpret_cast(pDevice->map(0, epmSize)); } uintptr_t @@ -51,8 +53,7 @@ PhysicalEnclaveMemory::readMem(uintptr_t src, size_t size) { void PhysicalEnclaveMemory::writeMem(uintptr_t src, uintptr_t offset, size_t size) { assert(pDevice); - void* va_dst = pDevice->map(offset, size); - memcpy(va_dst, reinterpret_cast(src), size); + memcpy(reinterpret_cast(vaStartAddr + offset), reinterpret_cast(src), size); } } // namespace Keystone diff --git a/sm/src/attest.c b/sm/src/attest.c index 9dcd87519..1e503e730 100644 --- a/sm/src/attest.c +++ b/sm/src/attest.c @@ -6,63 +6,116 @@ #include #include "page.h" #include +// #include -int measure_res_arr(resource_hash_t* elem, resource_hash_t* end, hash_ctx* hash_ctx) { +int strcmp(const char* left, const char* right) { + for (; *left != '\0'; left++, right++) { + if (*left != *right) { + return (*left - *right); + } + if (*right == '\0') { + return -1; + } + } + if (*right != '\0') { + return 1; + } + return 0; +} + +int validate_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, uintptr_t elem_size) { + uintptr_t start = ebase + start_off; + uintptr_t end = ebase + end_off; + if (start_off > end_off // bad loop condition + || end_off > efilled_size // out of bounds reads + || ebase >= start || ebase >= end // overflow + || (end - start) % elem_size != 0 ) { // hanging read + return 1; + } + return 0; +} + +int measure_absent_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { + if(validate_arr(ebase, efilled_size, start_off, end_off, sizeof(resource_hash_t))) { + return 1; + } + resource_hash_t* elem = (resource_hash_t*) (ebase + start_off); + resource_hash_t* end = (resource_hash_t*) (ebase + end_off); for (; elem < end; elem++) { - hash_extend(hash_ctx, elem, sizeof(elem[0])); + hash_extend(ctx, (void*) elem, sizeof(resource_hash_t)); } return 0; } -int measure_res_arr(resource_ptr_t* elem, resource_ptr_t* end, hash_ctx* hash_ctx, void* limit) { - for (; elem < end; elem++) { - hash_extend(hash_ctx, elem->name, sizeof(elem->name)); - hash_extend(hash_ctx, elem->type, sizeof(elem->type)); - if (elem->offset + elem->size >= limit) { - return 1; - } - hash_extend(hash_ctx, (void*) elem->offset, elem->size); // TODO: is > page ok? - } - return 0; +int measure_resident_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { + if(validate_arr(ebase, efilled_size, start_off, end_off, sizeof(resource_ptr_t))) { + return 1; + } + resource_ptr_t* elem = (resource_ptr_t*) (ebase + start_off); + resource_ptr_t* end = (resource_ptr_t*) (ebase + end_off); + for (; elem < end; elem++) { + hash_extend(ctx, (char*) elem->name, sizeof(elem->name)); + hash_extend(ctx, (char*) &elem->type, sizeof(elem->type)); + if (elem->offset >= elem->offset + elem->size + || elem->offset + elem->size > efilled_size) { + return 1; + } + hash_extend(ctx, (char*) (ebase + elem->offset), elem->size); // TODO(Evgeny): is > page ok? + } + return 0; +} + +int measure_runtime_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { + if(validate_arr(ebase, efilled_size, start_off, end_off, sizeof(runtime_val_t))) { + return 1; + } + runtime_val_t* elem = (runtime_val_t*) (ebase + start_off); + runtime_val_t* end = (runtime_val_t*) (ebase + end_off); + for (; elem < end; elem++) { + hash_extend(ctx, (void*) elem, sizeof(runtime_val_t)); + } + return 0; } unsigned long validate_and_hash_enclave(struct enclave* enclave){ - // TODO(Evgeny): move discovery into enclave uintptr_t ebase = enclave->params.dram_base; enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) ebase; - for (resource_ptr_t* id_res_resource = ebundle_h->id_res_arr; id_res_resource < ebundle_h->id_abs_arr; id_res_resource++) { - if (strcmp(id_res_resource->name, "loader") == 0) { - enclave->params.loader_base = ebase + id_res_resource->offset; - } - if (strcmp(id_res_resource->name, "runtime") == 0) { - enclave->params.runtime_base = ebase + id_res_resource->offset; - } - if (strcmp(id_res_resource->name, "eapp") == 0) { - enclave->params.user_base = ebase + id_res_resource->offset; - } - } - if (!enclave->params.loader_base || !enclave->params.runtime_base || !enclave->params.user_base) { - return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; - } - void* free = (void *) enclave->params.free_base; + uintptr_t efilled_size = enclave->params.free_base - ebase; - // TODO: ensure untrusted and free sizes + // TODO(Evgeny): ensure untrusted and free sizes // hash the epm contents hash_ctx ctx; hash_init(&ctx); bool fail_state = 0; - // fail_state |= measure_res_arr((void *) ebase + ebundle_h->runtime_arr, (void *) ebase + ebundle_h->id_res_arr, &ctx); - fail_state |= measure_res_arr(ebase + ebundle_h->id_res_arr, ebase + ebundle_h->id_abs_arr, &ctx, free); - fail_state |= measure_res_arr(ebase + ebundle_h->id_abs_arr, ebase + ebundle_h->res_arr, &ctx); + fail_state |= measure_runtime_arr(ebase, efilled_size, ebundle_h->runtime_arr, ebundle_h->id_res_arr, &ctx); + fail_state |= measure_resident_arr(ebase, efilled_size, ebundle_h->id_res_arr, ebundle_h->id_abs_arr, &ctx); + fail_state |= measure_absent_arr(ebase, efilled_size, ebundle_h->id_abs_arr, ebundle_h->res_arr, &ctx); hash_ctx ctx_copy = ctx; hash_finalize(enclave->identity, &ctx_copy); - fail_state |= measure_res_arr(ebase + ebundle_h->res_arr, ebase + ebundle_h->abs_arr, &ctx, free); - fail_state |= measure_res_arr(ebase + ebundle_h->abs_arr, ebase + ebundle_h->data, &ctx); + fail_state |= measure_resident_arr(ebase, efilled_size, ebundle_h->res_arr, ebundle_h->abs_arr, &ctx); + fail_state |= measure_absent_arr(ebase, efilled_size, ebundle_h->abs_arr, ebundle_h->data, &ctx); if (fail_state) { - return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; + return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; } hash_finalize(enclave->hash, &ctx); + // TODO(Evgeny): move discovery into enclave + resource_ptr_t* id_res_resource = (resource_ptr_t*) (ebase + ebundle_h->id_res_arr); + resource_ptr_t* id_abs_arr = (resource_ptr_t*) (ebase + ebundle_h->id_abs_arr); + // note: no overflow/ out of bounds possible because measure_resident_arr would have failed + for (; id_res_resource < id_abs_arr; id_res_resource++) { + if (strcmp(id_res_resource->name, "loader") == 0) { + enclave->params.loader_base = ebase + id_res_resource->offset; + } else if (strcmp(id_res_resource->name, "runtime") == 0) { + enclave->params.runtime_base = ebase + id_res_resource->offset; + } else if (strcmp(id_res_resource->name, "eapp") == 0) { + enclave->params.user_base = ebase + id_res_resource->offset; + } + } + if (!enclave->params.loader_base || !enclave->params.runtime_base || !enclave->params.user_base) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; // TODO(Evgeny): incorrect error type + } + return SBI_ERR_SM_ENCLAVE_SUCCESS; } diff --git a/sm/src/enclave.c b/sm/src/enclave.c index ff1bb4af4..1ebc387cc 100644 --- a/sm/src/enclave.c +++ b/sm/src/enclave.c @@ -52,7 +52,7 @@ static inline void context_switch_to_enclave(struct sbi_trap_regs* regs, if(load_parameters) { // passing parameters for a first run - regs->mepc = (uintptr_t) enclaves[eid].params.dram_base - 4; // regs->mepc will be +4 before sbi_ecall_handler return + regs->mepc = (uintptr_t) enclaves[eid].params.loader_base - 4; // regs->mepc will be +4 before sbi_ecall_handler return regs->mstatus = (1 << MSTATUS_MPP_SHIFT); // $a1: (PA) DRAM base, regs->a1 = (uintptr_t) enclaves[eid].params.dram_base; @@ -275,7 +275,7 @@ static unsigned long copy_enclave_report(struct enclave* enclave, static int is_create_args_valid(struct keystone_sbi_create_t* args) { - uintptr_t epm_start, epm_end; + uintptr_t epm_size; /* printm("[create args info]: \r\n\tepm_addr: %llx\r\n\tepmsize: %llx\r\n\tutm_addr: %llx\r\n\tutmsize: %llx\r\n\truntime_addr: %llx\r\n\tuser_addr: %llx\r\n\tfree_addr: %llx\r\n", */ /* args->epm_region.paddr, */ @@ -298,25 +298,12 @@ static int is_create_args_valid(struct keystone_sbi_create_t* args) args->utm_region.paddr + args->utm_region.size) return 0; - epm_start = args->epm_region.paddr; - epm_end = args->epm_region.paddr + args->epm_region.size; + epm_size = args->epm_region.size; - // check if physical addresses are in the range - if (args->runtime_paddr < epm_start || - args->runtime_paddr >= epm_end) - return 0; - if (args->user_paddr < epm_start || - args->user_paddr >= epm_end) - return 0; - if (args->free_paddr < epm_start || - args->free_paddr > epm_end) - // note: free_paddr == epm_end if there's no free memory - return 0; - - // check the order of physical addresses - if (args->runtime_paddr > args->user_paddr) - return 0; - if (args->user_paddr > args->free_paddr) + // check if free_offset is in range + if (args->free_offset <= 0 || + args->free_offset > epm_size) + // note: free_offset == epm_size if there's no free memory return 0; return 1; @@ -355,7 +342,7 @@ unsigned long create_enclave(unsigned long *eidptr, struct keystone_sbi_create_t struct runtime_params_t params; params.dram_base = base; params.dram_size = size; - params.free_base = create_args.free_paddr; + params.free_base = base + create_args.free_offset; params.untrusted_base = utbase; params.untrusted_size = utsize; From 041a1b44bf7a3e5162f2601a6d33d4f5dc2ea9c0 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Sat, 23 Mar 2024 14:47:29 -0700 Subject: [PATCH 3/8] cleaned up sdk, redid memory management --- sdk/include/host/ElfFile.hpp | 4 + sdk/include/host/Enclave.hpp | 53 ++--- sdk/include/host/Error.hpp | 1 + sdk/include/host/KeystoneDevice.hpp | 46 ++--- sdk/include/host/Memory.hpp | 94 --------- sdk/src/host/CMakeLists.txt | 3 - sdk/src/host/Enclave.cpp | 245 ++++++++++-------------- sdk/src/host/KeystoneDevice.cpp | 90 ++++----- sdk/src/host/Memory.cpp | 49 ----- sdk/src/host/PhysicalEnclaveMemory.cpp | 59 ------ sdk/src/host/SimulatedEnclaveMemory.cpp | 51 ----- sdk/src/host/hash_util.cpp | 1 - 12 files changed, 180 insertions(+), 516 deletions(-) delete mode 100644 sdk/include/host/Memory.hpp delete mode 100644 sdk/src/host/Memory.cpp delete mode 100644 sdk/src/host/PhysicalEnclaveMemory.cpp delete mode 100644 sdk/src/host/SimulatedEnclaveMemory.cpp diff --git a/sdk/include/host/ElfFile.hpp b/sdk/include/host/ElfFile.hpp index ec2b24e97..0cc38d4a4 100644 --- a/sdk/include/host/ElfFile.hpp +++ b/sdk/include/host/ElfFile.hpp @@ -43,6 +43,10 @@ class ElfFile { uintptr_t getEntryPoint(); void* getProgramSegment(size_t ph); + // delete copy constructors because ~ElfFile() unmaps + ElfFile (const ElfFile&) = delete; + ElfFile& operator= (const ElfFile&) = delete; + private: int filep; diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index ee93e33c6..17928d744 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -24,8 +24,8 @@ extern "C" { #include "ElfFile.hpp" #include "Error.hpp" #include "KeystoneDevice.hpp" -#include "Memory.hpp" #include "Params.hpp" +#include "hash_util.hpp" namespace Keystone { @@ -34,24 +34,10 @@ typedef std::function OcallFunc; class Enclave { private: Params params; - uintptr_t runtimeElfAddr; - uintptr_t enclaveElfAddr; - Memory* pMemory; KeystoneDevice* pDevice; - void* shared_buffer; - size_t shared_buffer_size; OcallFunc oFuncDispatch; - bool mapUntrusted(size_t size); - void copyMem(uintptr_t dest_offset, uintptr_t src, size_t size); - void copyFile(uintptr_t filePtr, size_t fileSize); - void allocUninitialized(ElfFile* elfFile); - void loadElf(ElfFile* elfFile); - - bool initFiles(const char*, const char*); - bool initDevice(); - bool prepareEnclaveMemory(size_t requiredPages, uintptr_t alternatePhysAddr); - bool initMemory(); + // track added resources typedef struct { char name[MSR_NAME_LEN]; uintptr_t type; @@ -61,34 +47,37 @@ class Enclave { std::vector identityAbsent; std::vector resident; std::vector absent; - void* enclave_base = 0; - uintptr_t materializeResourceInfo(resource_ptr_t* residentResPtrs, - ElfFile** allElfFiles, std::vector resInfos); + std::vector allElfFiles; + + static uint64_t calculateEpmPages(std::vector allElfFiles, size_t freeMemSize); + // linearly advances as we write to epm + uintptr_t epmFreeOffset; + /* Returns va to write to free epm after marking size bytes rounded up unfree. + Copies and 0-pads from src if given. */ + uintptr_t useEpm(uintptr_t src, uintptr_t size); + /* Iterates resident resources registered with the class and puts the files + and their pointers into the enclave bundle in epm. */ + Error materializeResourceInfo(resource_ptr_t residentResPtrs[], + ElfFile* allElfFiles[], std::vector resInfos); + static void measureElfFile(hash_ctx_t* hash_ctx, ElfFile& file); public: Enclave(); ~Enclave(); static Error measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath); + // shared buffer is utm void* getSharedBuffer(); size_t getSharedBufferSize(); - Memory* getMemory(); - uintptr_t getRuntimeElfAddr() { return runtimeElfAddr; } - uintptr_t getEnclaveElfAddr() { return enclaveElfAddr; } Error registerOcallDispatch(OcallFunc func); + // TODO(Evgeny): rename init to something else. finalize? Error init(const char* filepath, const char* runtime, const char* loaderpath, Params parameters); - Error init( - const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params, - uintptr_t alternatePhysAddr); Error destroy(); Error run(uintptr_t* ret = nullptr); - // TODO(Evgeny): switch to errors. Currently, 0 = success, 1 = error. - uintptr_t addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity); - uintptr_t addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity); - uintptr_t finalize(uintptr_t alternatePhysAddr = 0); + Error addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity); + Error addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity); + // Call after adding all needed resources to fully create the enclave. + Error finalize(); }; -uint64_t -calculate_required_pages(ElfFile** elfFiles, size_t numElfFiles); - } // namespace Keystone diff --git a/sdk/include/host/Error.hpp b/sdk/include/host/Error.hpp index f241bc650..6fb038ba2 100644 --- a/sdk/include/host/Error.hpp +++ b/sdk/include/host/Error.hpp @@ -25,6 +25,7 @@ enum class Error { PageAllocationFailure, EdgeCallHost, EnclaveInterrupted, + BadArgument, }; } // namespace Keystone diff --git a/sdk/include/host/KeystoneDevice.hpp b/sdk/include/host/KeystoneDevice.hpp index 3833ce890..90e0857ba 100644 --- a/sdk/include/host/KeystoneDevice.hpp +++ b/sdk/include/host/KeystoneDevice.hpp @@ -25,46 +25,38 @@ namespace Keystone { class KeystoneDevice { protected: - int eid; - uintptr_t physAddr; + int eid = 0; + bool finalizeDone = false; + uintptr_t epmPhysAddr = 0, epmSize = 0, epmVirtAddr = 0; + uintptr_t utmPhysAddr = 0, utmSize = 0, utmVirtAddr = 0; private: int fd; Error __run(bool resume, uintptr_t* ret); + // map maps epm before finalize and utm after. + virtual uintptr_t map(uintptr_t addr, size_t size); public: - virtual uintptr_t getPhysAddr() { return physAddr; } + uintptr_t getEpmPhysAddr() { return epmPhysAddr; } + uintptr_t getEpmSize() { return epmSize; } + uintptr_t getEpmVirtAddr() { return epmVirtAddr; } + uintptr_t getUtmPhysAddr() { return utmPhysAddr; } + uintptr_t getUtmSize() { return utmSize; } + uintptr_t getUtmVirtAddr() { return utmVirtAddr; } KeystoneDevice(); virtual ~KeystoneDevice() {} - virtual bool initDevice(Params params); + virtual Error initDevice(Params params); virtual Error create(uint64_t minPages); - virtual uintptr_t initUTM(size_t size); - virtual Error finalize(uintptr_t free_offset); + virtual Error initUTM(size_t size); + virtual Error finalize(uintptr_t freeOffset); virtual Error destroy(); virtual Error run(uintptr_t* ret); virtual Error resume(uintptr_t* ret); - virtual void* map(uintptr_t addr, size_t size); -}; - -class MockKeystoneDevice : public KeystoneDevice { - private: - /* allocated buffer with map() */ - void* sharedBuffer; - - public: - MockKeystoneDevice() {} - ~MockKeystoneDevice(); - bool initDevice(Params params); - Error create(uint64_t minPages); - uintptr_t initUTM(size_t size); - Error finalize( - uintptr_t runtimePhysAddr, uintptr_t eappPhysAddr, uintptr_t freePhysAddr, - uintptr_t freeRequested); - Error destroy(); - Error run(uintptr_t* ret); - Error resume(uintptr_t* ret); - void* map(uintptr_t addr, size_t size); + // pre-finalize only + virtual Error mapEpm(); + // post-finalize only + virtual Error mapUtm(); }; } // namespace Keystone diff --git a/sdk/include/host/Memory.hpp b/sdk/include/host/Memory.hpp deleted file mode 100644 index f5e290949..000000000 --- a/sdk/include/host/Memory.hpp +++ /dev/null @@ -1,94 +0,0 @@ -//****************************************************************************** -// Copyright (c) 2018, The Regents of the University of California (Regents). -// All Rights Reserved. See LICENSE for license details. -//------------------------------------------------------------------------------ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "./common.h" -#include "KeystoneDevice.hpp" -#include "hash_util.hpp" - -namespace Keystone { - -class Memory { - public: - Memory(); - ~Memory() {} - virtual void init( - KeystoneDevice* dev, uintptr_t phys_addr, size_t min_pages) = 0; - virtual uintptr_t readMem(uintptr_t src, size_t size) = 0; - virtual void writeMem(uintptr_t src, uintptr_t dst, size_t size) = 0; - virtual uintptr_t allocMem(size_t size) = 0; - virtual uintptr_t allocUtm(size_t size) = 0; - size_t epmAllocVspace(uintptr_t addr, size_t num_pages); - uintptr_t allocPages(size_t size); - - - // getters to be deprecated - uintptr_t getStartAddr() { return startAddr; } - uintptr_t getCurrentOffset() { return epmFreeList; } - uintptr_t getCurrentEPMAddress() { return epmFreeList + startAddr; } - - void startRuntimeMem(); - void startEappMem(); - void startFreeMem(); - - void incrementEPMFreeList(); - - uintptr_t getRuntimePhysAddr() { return runtimePhysAddr; } - uintptr_t getEappPhysAddr() { return eappPhysAddr; } - uintptr_t getFreePhysAddr() { return freePhysAddr; } - uintptr_t getUTMPhysAddr() { return utmPhysAddr; } - - KeystoneDevice* pDevice; - size_t epmSize; - uintptr_t epmFreeList; - uintptr_t startAddr; - uintptr_t vaStartAddr; - - // Keystone Device runtime params - uintptr_t runtimePhysAddr; - uintptr_t eappPhysAddr; - uintptr_t freePhysAddr; - uintptr_t utmPhysAddr; - uintptr_t untrustedPtr; - uintptr_t untrustedSize; -}; - -class PhysicalEnclaveMemory : public Memory { - public: - PhysicalEnclaveMemory() {} - ~PhysicalEnclaveMemory() {} - void init(KeystoneDevice* dev, uintptr_t phys_addr, size_t min_pages); - uintptr_t readMem(uintptr_t src, size_t size); - void writeMem(uintptr_t src, uintptr_t dst, size_t size); - uintptr_t allocMem(size_t size); - uintptr_t allocUtm(size_t size); -}; - -// Simulated memory reads/writes from calloc'ed memory -class SimulatedEnclaveMemory : public Memory { - private: - void* allocateAligned(size_t size, size_t alignment); - - public: - SimulatedEnclaveMemory() {} - ~SimulatedEnclaveMemory() {} - void init(KeystoneDevice* dev, uintptr_t phys_addr, size_t min_pages); - uintptr_t readMem(uintptr_t src, size_t size); - void writeMem(uintptr_t src, uintptr_t dst, size_t size); - uintptr_t allocMem(size_t size); - uintptr_t allocUtm(size_t size); -}; - -} // namespace Keystone diff --git a/sdk/src/host/CMakeLists.txt b/sdk/src/host/CMakeLists.txt index 27584a11a..52bfb1cd2 100644 --- a/sdk/src/host/CMakeLists.txt +++ b/sdk/src/host/CMakeLists.txt @@ -11,9 +11,6 @@ set(SOURCE_FILES ElfFile.cpp KeystoneDevice.cpp Enclave.cpp - Memory.cpp - PhysicalEnclaveMemory.cpp - SimulatedEnclaveMemory.cpp ) set(INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/include/host) diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index edd04248a..4d0887422 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -11,7 +11,6 @@ extern "C" { #include "shared/keystone_user.h" } #include "ElfFile.hpp" -#include "hash_util.hpp" namespace Keystone { @@ -23,12 +22,11 @@ Enclave::~Enclave() { } uint64_t -calculate_required_pages(ElfFile** elfFiles, size_t numElfFiles) { - uint64_t req_pages = 0; +Enclave::calculateEpmPages(std::vector allElfFiles, size_t freeMemSize) { + uint64_t pages = 0; - for (int i = 0; i < numElfFiles; i++) { - ElfFile* elfFile = elfFiles[i]; - req_pages += ceil(elfFile->getFileSize() / PAGE_SIZE); + for (ElfFile* elfFile : allElfFiles) { + pages += PAGE_UP(elfFile->getFileSize()) / PAGE_SIZE; } /* FIXME: calculate the required number of pages for the page table. * We actually don't know how many page tables the enclave might need, @@ -45,65 +43,18 @@ calculate_required_pages(ElfFile** elfFiles, size_t numElfFiles) { /* Add one page each for bss segments of runtime and eapp */ // TODO: add space for stack? - req_pages += 16; - return req_pages; -} + pages += 16; -bool -Enclave::prepareEnclaveMemory(size_t requiredPages, uintptr_t alternatePhysAddr) { // FIXME: this will be deprecated with complete freemem support. // We just add freemem size for now. - uint64_t minPages; - minPages = ROUND_UP(params.getFreeMemSize(), PAGE_BITS) / PAGE_SIZE; - minPages += requiredPages; - - /* Call Enclave Driver */ - if (pDevice->create(minPages) != Error::Success) { - return false; - } - - /* We switch out the phys addr as needed */ - uintptr_t physAddr; - if (alternatePhysAddr) { - physAddr = alternatePhysAddr; - } else { - physAddr = pDevice->getPhysAddr(); - } - - pMemory->init(pDevice, physAddr, minPages); - return true; + pages += PAGE_UP(freeMemSize) / PAGE_SIZE; + return pages; } void -Enclave::copyFile(uintptr_t filePtr, size_t fileSize) { - uintptr_t startOffset = pMemory->getCurrentOffset(); - size_t bytesRemaining = fileSize; - - uintptr_t currOffset; - while (bytesRemaining > 0) { - currOffset = pMemory->getCurrentOffset(); - pMemory->incrementEPMFreeList(); - - size_t bytesToWrite = (bytesRemaining > PAGE_SIZE) ? PAGE_SIZE : bytesRemaining; - size_t bytesWritten = fileSize - bytesRemaining; - - // need 0 padding for hashes to be consistent, - // and to keep code aligned to be able to map page-wise without copying. - if (bytesToWrite < PAGE_SIZE) { - char page[PAGE_SIZE]; - memset(page, 0, PAGE_SIZE); - memcpy(page, (const void*) (filePtr + bytesWritten), (size_t)(bytesToWrite)); - pMemory->writeMem((uintptr_t) page, currOffset, PAGE_SIZE); - } else { - pMemory->writeMem(filePtr + bytesWritten, currOffset, bytesToWrite); - } - bytesRemaining -= bytesToWrite; - } -} - -static void measureElfFile(hash_ctx_t* hash_ctx, ElfFile* file) { - uintptr_t fptr = (uintptr_t) file->getPtr(); - uintptr_t fend = fptr + (uintptr_t) file->getFileSize(); +Enclave::measureElfFile(hash_ctx_t* hash_ctx, ElfFile& file) { + uintptr_t fptr = (uintptr_t) file.getPtr(); + uintptr_t fend = fptr + (uintptr_t) file.getFileSize(); for (; fptr < fend; fptr += PAGE_SIZE) { if (fend - fptr < PAGE_SIZE) { @@ -130,11 +81,11 @@ Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, cons PAGE_UP(eapp->getFileSize()) }; hash_extend(&hash_ctx, (void*) sizes, sizeof(sizes)); - measureElfFile(&hash_ctx, loader); + measureElfFile(&hash_ctx, *loader); delete loader; - measureElfFile(&hash_ctx, runtime); + measureElfFile(&hash_ctx, *runtime); delete runtime; - measureElfFile(&hash_ctx, eapp); + measureElfFile(&hash_ctx, *eapp); delete eapp; hash_finalize(hash, &hash_ctx); @@ -142,11 +93,10 @@ Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, cons return Error::Success; } -// TODO(Evgeny): switch to errors. Currently, 0 = success, 1 = error. -uintptr_t +Error Enclave::addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity) { if (strlen(name) >= MSR_NAME_LEN) { - return 1; + return Error::BadArgument; } resource_info_t* resInfo = 0; if (identity) { @@ -159,13 +109,13 @@ Enclave::addResidentResource(const char* name, uintptr_t type, const char* filep strcpy(resInfo->name, name); resInfo->type = type; resInfo->filepath = std::string(filepath); - return 0; + return Error::Success; } -uintptr_t +Error Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity) { if (strlen(name) >= MSR_NAME_LEN) { - return 1; + return Error::BadArgument; } resource_hash_t* resHash = 0; if (identity) { @@ -178,11 +128,29 @@ Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, b strcpy(resHash->name, name); resHash->type = type; memcpy(resHash->hash, hash, MDSIZE); - return 0; + return Error::Success; } uintptr_t -Enclave::materializeResourceInfo(resource_ptr_t* residentResPtrs, ElfFile** elfFiles, +Enclave::useEpm(uintptr_t src, uintptr_t size) { + if (!size) { + return pDevice->getEpmVirtAddr() + epmFreeOffset; + } + uintptr_t allocatedOffset = epmFreeOffset; + epmFreeOffset = PAGE_UP(epmFreeOffset + size); + assert(epmFreeOffset > allocatedOffset); // no overflow + assert(epmFreeOffset <= pDevice->getEpmSize() - params.getFreeMemSize()); // free mem remaining + uintptr_t dest_va = pDevice->getEpmVirtAddr() + allocatedOffset; + if (src) { + memcpy((void*) dest_va, (void*) src, size); + uintptr_t end_va = dest_va + size; + memset((void*) end_va, 0, pDevice->getEpmVirtAddr() + epmFreeOffset - end_va); + } + return dest_va; +} + +Error +Enclave::materializeResourceInfo(resource_ptr_t residentResPtrs[], ElfFile* elfFiles[], std::vector resInfos) { for (uintptr_t i = 0; i < resInfos.size(); i++) { const resource_info_t& resInfo = resInfos[i]; @@ -190,50 +158,50 @@ Enclave::materializeResourceInfo(resource_ptr_t* residentResPtrs, ElfFile** elfF resource_ptr_t* resPtr = residentResPtrs + i; strcpy(resPtr->name, resInfo.name); resPtr->type = resInfo.type; - resPtr->offset = pMemory->getCurrentOffset(); + resPtr->offset = useEpm((uintptr_t) elfFile->getPtr(), elfFile->getFileSize()) - pDevice->getEpmVirtAddr(); resPtr->size = (uintptr_t) elfFile->getFileSize(); - copyFile((uintptr_t) elfFile->getPtr(), elfFile->getFileSize()); } - return 0; + return Error::Success; } -uintptr_t -Enclave::finalize(uintptr_t alternatePhysAddr) { +Error +Enclave::finalize() { // TODO(Evgeny): ensure this is not called twice, no adds after, etc. - // TODO(Evgeny): how is alternatePhysAddr useful? + // TODO(Evgeny): improve error messages + // TODO(Evgeny): add comments to functions - pMemory = new PhysicalEnclaveMemory(); + Error err = Error::Success; pDevice = new KeystoneDevice(); + epmFreeOffset = 0; - if (!pDevice->initDevice(params)) { + err = pDevice->initDevice(params); + if (err != Error::Success) { destroy(); - return 1; - // return Error::DeviceInitFailure; + return err; } // allocate enclave memory - std::vector allElfFiles; for (const resource_info_t& res_info : identityResident) { allElfFiles.push_back(new ElfFile(res_info.filepath)); } for (const resource_info_t& res_info : resident) { allElfFiles.push_back(new ElfFile(res_info.filepath)); } - size_t requiredPages = calculate_required_pages(&allElfFiles[0], allElfFiles.size()); - if (!prepareEnclaveMemory(requiredPages, alternatePhysAddr)) { + uint64_t requiredPages = calculateEpmPages(allElfFiles, params.getFreeMemSize()); + err = pDevice->create(requiredPages); + if (err != Error::Success) { destroy(); - return 1; - // return Error::DeviceError; + return err; } - if (!pMemory->allocUtm(params.getUntrustedSize())) { + err = pDevice->initUTM(params.getUntrustedSize()); + if (err != Error::Success) { ERROR("failed to init untrusted memory - ioctl() failed"); destroy(); - return 1; - // return Error::DeviceError; + return err; } - uintptr_t va_epm = pMemory->vaStartAddr; - enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) va_epm; + uintptr_t ebase = useEpm(0, 0); + enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) ebase; // space out the arrays ebundle_h->runtime_arr = (uintptr_t) sizeof(enclave_bundle_header_t); @@ -246,76 +214,68 @@ Enclave::finalize(uintptr_t alternatePhysAddr) { + (uintptr_t) (sizeof(resource_ptr_t) * resident.size()); ebundle_h->data = ebundle_h->abs_arr + (uintptr_t) (sizeof(resource_hash_t) * absent.size()); - pMemory->epmFreeList = ROUND_UP(ebundle_h->data, PAGE_BITS); + useEpm(0, ebundle_h->data); // contiguous ebundle_h and arrays, then page padding // fill in the arrays & data // TODO(Evgeny): runtime values - memcpy((void*) (va_epm + ebundle_h->id_abs_arr), &identityAbsent[0], sizeof(resource_hash_t) * identityAbsent.size()); - memcpy((void*) (va_epm + ebundle_h->abs_arr), &absent[0], sizeof(resource_hash_t) * absent.size()); - materializeResourceInfo((resource_ptr_t*) (va_epm + ebundle_h->id_res_arr), &allElfFiles[0], identityResident); - // copyFile((uintptr_t) &tempIdentityResidentResourcePtrs[0], sizeof(resource_hash_t) * tempIdentityResidentResourcePtrs.size()); - // std::vector tempResidentResourcePtrs; - // materializeResourceInfo(tempResidentResourcePtrs, &allElfFiles[identityResident.size()], resident); - // copyFile((uintptr_t) &tempResidentResourcePtrs[0], sizeof(resource_hash_t) * tempResidentResourcePtrs.size()); - - if (pDevice->finalize(pMemory->getCurrentOffset()) != Error::Success) { + memcpy((void*) (ebase + ebundle_h->id_abs_arr), &identityAbsent[0], sizeof(resource_hash_t) * identityAbsent.size()); + memcpy((void*) (ebase + ebundle_h->abs_arr), &absent[0], sizeof(resource_hash_t) * absent.size()); + materializeResourceInfo((resource_ptr_t*) (ebase + ebundle_h->id_res_arr), &allElfFiles[0], identityResident); + materializeResourceInfo((resource_ptr_t*) (ebase + ebundle_h->res_arr), &allElfFiles[identityResident.size()], resident); + + // finalize creating enclave + err = pDevice->finalize(epmFreeOffset); + if (err != Error::Success) { destroy(); - return 1; - // return Error::DeviceError; + return err; } - if (!mapUntrusted(params.getUntrustedSize())) { + err = pDevice->mapUtm(); + if (err != Error::Success) { ERROR( "failed to finalize enclave - cannot obtain the untrusted buffer " "pointer \n"); destroy(); - return 1; - // return Error::DeviceMemoryMapError; + return err; } - // TODO(Evgeny): validate that loader, runtime, and eapp are present - return 0; + // TODO(Evgeny): validate that loader is present + return Error::Success; } Error Enclave::init(const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params) { - return this->init(eapppath, runtimepath, loaderpath, _params, (uintptr_t)0); -} - -Error -Enclave::init( - const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params, - uintptr_t alternatePhysAddr) { params = _params; - // TODO(Evgeny): errors - addResidentResource("loader", 0, loaderpath, true); - addResidentResource("runtime", 0, runtimepath, true); - addResidentResource("eapp", 0, eapppath, true); - finalize(alternatePhysAddr); - - return Error::Success; -} - -bool -Enclave::mapUntrusted(size_t size) { - if (size == 0) { - return true; + Error err = Error::Success; + err = addResidentResource("loader", 0, loaderpath, true); + if (err != Error::Success) { + ERROR("failed to add loader with path %s", loaderpath); + return err; } - - shared_buffer = pDevice->map(0, size); - - if (shared_buffer == NULL) { - return false; + err = addResidentResource("runtime", 0, runtimepath, true); + if (err != Error::Success) { + ERROR("failed to add runtime with path %s", loaderpath); + return err; } - - shared_buffer_size = size; - - return true; + err = addResidentResource("eapp", 0, eapppath, true); + if (err != Error::Success) { + ERROR("failed to add eapp with path %s", loaderpath); + return err; + } + err = finalize(); + + return err; } Error Enclave::destroy() { - return pDevice->destroy(); + for (ElfFile* elfFile : allElfFiles) { + delete elfFile; + } + allElfFiles.clear(); + Error err = pDevice->destroy(); + delete pDevice; + return err; } Error @@ -340,17 +300,14 @@ Enclave::run(uintptr_t* retval) { void* Enclave::getSharedBuffer() { - return shared_buffer; + assert(pDevice->getUtmVirtAddr()); + return (void*) pDevice->getUtmVirtAddr(); } size_t Enclave::getSharedBufferSize() { - return shared_buffer_size; -} - -Memory* -Enclave::getMemory() { - return pMemory; + assert(pDevice->getUtmSize()); + return pDevice->getUtmSize(); } Error diff --git a/sdk/src/host/KeystoneDevice.cpp b/sdk/src/host/KeystoneDevice.cpp index f5ccb74a3..15edcb525 100644 --- a/sdk/src/host/KeystoneDevice.cpp +++ b/sdk/src/host/KeystoneDevice.cpp @@ -20,34 +20,39 @@ KeystoneDevice::create(uint64_t minPages) { return Error::IoctlErrorCreate; } - eid = encl.eid; - physAddr = encl.epm_paddr; + eid = encl.eid; + epmPhysAddr = encl.epm_paddr; + epmSize = encl.epm_size; + mapEpm(); return Error::Success; } -uintptr_t +Error KeystoneDevice::initUTM(size_t size) { struct keystone_ioctl_create_enclave encl; encl.eid = eid; encl.utm_size = size; if (ioctl(fd, KEYSTONE_IOC_UTM_INIT, &encl)) { - return 0; + return Error::DeviceError; } + utmPhysAddr = encl.utm_paddr; + utmSize = size; - return encl.utm_paddr; + return Error::Success; } Error -KeystoneDevice::finalize(uintptr_t free_offset) { +KeystoneDevice::finalize(uintptr_t freeOffset) { struct keystone_ioctl_create_enclave encl; encl.eid = eid; - encl.free_offset = free_offset; + encl.free_offset = freeOffset; if (ioctl(fd, KEYSTONE_IOC_FINALIZE_ENCLAVE, &encl)) { perror("ioctl error"); return Error::IoctlErrorFinalize; } + finalizeDone = true; return Error::Success; } @@ -117,72 +122,45 @@ KeystoneDevice::resume(uintptr_t* ret) { return __run(true, ret); } -void* +uintptr_t KeystoneDevice::map(uintptr_t addr, size_t size) { assert(fd >= 0); void* ret; ret = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr); assert(ret != MAP_FAILED); - return ret; -} - -bool -KeystoneDevice::initDevice(Params params) { // TODO: why does this need params - /* open device driver */ - fd = open(KEYSTONE_DEV_PATH, O_RDWR); - if (fd < 0) { - PERROR("cannot open device file"); - return false; - } - return true; -} - -Error -MockKeystoneDevice::create(uint64_t minPages) { - eid = -1; - return Error::Success; -} - -uintptr_t -MockKeystoneDevice::initUTM(size_t size) { - return 0; + assert(ret != 0); + return (uintptr_t) ret; } Error -MockKeystoneDevice::finalize( - uintptr_t runtimePhysAddr, uintptr_t eappPhysAddr, uintptr_t freePhysAddr, - uintptr_t freeRequested) { - return Error::Success; -} - -Error -MockKeystoneDevice::destroy() { +KeystoneDevice::mapEpm() { + assert(!finalizeDone); + if (!epmPhysAddr || !epmSize) { + return Error::DeviceError; + } + epmVirtAddr = map(0, epmSize); return Error::Success; } Error -MockKeystoneDevice::run(uintptr_t* ret) { +KeystoneDevice::mapUtm() { + assert(finalizeDone); + if (!utmPhysAddr || !utmSize) { + return Error::DeviceError; + } + utmVirtAddr = map(0, utmSize); return Error::Success; } Error -MockKeystoneDevice::resume(uintptr_t* ret) { +KeystoneDevice::initDevice(Params params) { // TODO: why does this need params + /* open device driver */ + fd = open(KEYSTONE_DEV_PATH, O_RDWR); + if (fd < 0) { + PERROR("cannot open device file"); + return Error::DeviceInitFailure; + } return Error::Success; } -bool -MockKeystoneDevice::initDevice(Params params) { - return true; -} - -void* -MockKeystoneDevice::map(uintptr_t addr, size_t size) { - sharedBuffer = malloc(size); - return sharedBuffer; -} - -MockKeystoneDevice::~MockKeystoneDevice() { - if (sharedBuffer) free(sharedBuffer); -} - } // namespace Keystone diff --git a/sdk/src/host/Memory.cpp b/sdk/src/host/Memory.cpp deleted file mode 100644 index b5e849160..000000000 --- a/sdk/src/host/Memory.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//****************************************************************************** -// Copyright (c) 2018, The Regents of the University of California (Regents). -// All Rights Reserved. See LICENSE for license details. -//------------------------------------------------------------------------------ -#include "Memory.hpp" - -#include - -#include "shared/keystone_user.h" - -namespace Keystone { - -Memory::Memory() { - epmFreeList = 0; - startAddr = 0; -} - -void -Memory::startRuntimeMem() { - runtimePhysAddr = getCurrentEPMAddress(); -} - -void -Memory::startEappMem() { - eappPhysAddr = getCurrentEPMAddress(); -} - -void -Memory::startFreeMem() { - freePhysAddr = getCurrentEPMAddress(); -} - -void -Memory::incrementEPMFreeList() { - epmFreeList += PAGE_SIZE; -} - -uintptr_t -Memory::allocPages(size_t size) { - uintptr_t addr = epmFreeList; - if (size % PAGE_SIZE > 0) { - epmFreeList += (size / PAGE_SIZE + 1) * PAGE_SIZE; - } else { - epmFreeList += (size / PAGE_SIZE) * PAGE_SIZE; - } - return addr; -} - -} // namespace Keystone diff --git a/sdk/src/host/PhysicalEnclaveMemory.cpp b/sdk/src/host/PhysicalEnclaveMemory.cpp deleted file mode 100644 index 402404ea0..000000000 --- a/sdk/src/host/PhysicalEnclaveMemory.cpp +++ /dev/null @@ -1,59 +0,0 @@ -//****************************************************************************** -// Copyright (c) 2018, The Regents of the University of California (Regents). -// All Rights Reserved. See LICENSE for license details. -//------------------------------------------------------------------------------ -#include "Memory.hpp" - -namespace Keystone { - -void -PhysicalEnclaveMemory::init( - KeystoneDevice* dev, uintptr_t phys_addr, size_t min_pages) { - pDevice = dev; - assert(pDevice); - // TODO(dayeol): need to set actual EPM size - epmSize = PAGE_SIZE * min_pages; - epmFreeList = 0; - startAddr = phys_addr; - vaStartAddr = reinterpret_cast(pDevice->map(0, epmSize)); -} - -uintptr_t -PhysicalEnclaveMemory::allocUtm(size_t size) { - uintptr_t ret = pDevice->initUTM(size); - untrustedSize = size; - utmPhysAddr = ret; - return ret; -} - -// TODO: delete this -/* Only used to allocate memory for root page table */ -uintptr_t -PhysicalEnclaveMemory::allocMem(size_t size) { - uintptr_t ret; - - assert(pDevice); - - ret = reinterpret_cast(pDevice->map(0, size)); - return ret; -} - -// unused -uintptr_t -PhysicalEnclaveMemory::readMem(uintptr_t src, size_t size) { - uintptr_t ret; - - assert(pDevice); - - ret = reinterpret_cast(pDevice->map(src, size)); - return ret; -} - -/* src: virtual address */ -void -PhysicalEnclaveMemory::writeMem(uintptr_t src, uintptr_t offset, size_t size) { - assert(pDevice); - memcpy(reinterpret_cast(vaStartAddr + offset), reinterpret_cast(src), size); -} - -} // namespace Keystone diff --git a/sdk/src/host/SimulatedEnclaveMemory.cpp b/sdk/src/host/SimulatedEnclaveMemory.cpp deleted file mode 100644 index 8317dd5f2..000000000 --- a/sdk/src/host/SimulatedEnclaveMemory.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//****************************************************************************** -// Copyright (c) 2018, The Regents of the University of California (Regents). -// All Rights Reserved. See LICENSE for license details. -//------------------------------------------------------------------------------ -#include "Memory.hpp" - -namespace Keystone { - -void -SimulatedEnclaveMemory::init( - KeystoneDevice* dev, uintptr_t phys_addr, size_t min_pages) { - pDevice = dev; - epmSize = PAGE_SIZE * min_pages; - epmFreeList = 0; // offset - startAddr = 0; -} - -void* -SimulatedEnclaveMemory::allocateAligned(size_t size, size_t alignment) { - const size_t mask = alignment - 1; - const uintptr_t mem = (uintptr_t)calloc(size + alignment, sizeof(char)); - return reinterpret_cast((mem + mask) & ~mask); -} - -// unused -uintptr_t -SimulatedEnclaveMemory::allocMem(size_t size) { - uintptr_t ret; - ret = (uintptr_t)allocateAligned(size, PAGE_SIZE); - return ret; -} - -uintptr_t -SimulatedEnclaveMemory::allocUtm(size_t size) { - utmPhysAddr = allocMem(size); - untrustedSize = size; - return utmPhysAddr; -} - -uintptr_t -SimulatedEnclaveMemory::readMem(uintptr_t src, size_t size) { - return src; -} - -// TODO: change write Mem to use addresses relative to start of section rather than absolute addresses -void -SimulatedEnclaveMemory::writeMem(uintptr_t src, uintptr_t dst, size_t size) { - memcpy(reinterpret_cast(dst), reinterpret_cast(src), size); -} - -} // namespace Keystone diff --git a/sdk/src/host/hash_util.cpp b/sdk/src/host/hash_util.cpp index 27fea89ee..b32e29674 100644 --- a/sdk/src/host/hash_util.cpp +++ b/sdk/src/host/hash_util.cpp @@ -5,7 +5,6 @@ extern "C" { #include "common/sha3.h" } -#include "Memory.hpp" #include "hash_util.hpp" #define RISCV_PGSIZE (1 << 12) From a1896e235f5358b8db5d1b5172b7a17538ad45a5 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Tue, 26 Mar 2024 13:10:17 -0700 Subject: [PATCH 4/8] measurement done, pDevice not pointer --- sdk/include/host/Enclave.hpp | 5 +- sdk/src/host/Enclave.cpp | 118 ++++++++++++++++++++--------------- sm/src/attest.c | 8 ++- 3 files changed, 78 insertions(+), 53 deletions(-) diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index 17928d744..fbffb7de8 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -34,7 +34,7 @@ typedef std::function OcallFunc; class Enclave { private: Params params; - KeystoneDevice* pDevice; + KeystoneDevice pDevice; OcallFunc oFuncDispatch; // track added resources @@ -59,11 +59,12 @@ class Enclave { and their pointers into the enclave bundle in epm. */ Error materializeResourceInfo(resource_ptr_t residentResPtrs[], ElfFile* allElfFiles[], std::vector resInfos); - static void measureElfFile(hash_ctx_t* hash_ctx, ElfFile& file); + static Error measureResidentArr(hash_ctx_t& hash_ctx, std::vector resident); public: Enclave(); ~Enclave(); + Error measureSelf(char* hash); static Error measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath); // shared buffer is utm void* getSharedBuffer(); diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index 4d0887422..e14857e0e 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -18,7 +18,7 @@ Enclave::Enclave() { } Enclave::~Enclave() { - destroy(); + assert(destroy() == Error::Success); } uint64_t @@ -51,45 +51,65 @@ Enclave::calculateEpmPages(std::vector allElfFiles, size_t freeMemSize return pages; } -void -Enclave::measureElfFile(hash_ctx_t* hash_ctx, ElfFile& file) { - uintptr_t fptr = (uintptr_t) file.getPtr(); - uintptr_t fend = fptr + (uintptr_t) file.getFileSize(); - - for (; fptr < fend; fptr += PAGE_SIZE) { - if (fend - fptr < PAGE_SIZE) { - char page[PAGE_SIZE]; - memset(page, 0, PAGE_SIZE); - memcpy(page, (const void*) fptr, (size_t)(fend-fptr)); - hash_extend_page(hash_ctx, (void*) page); - } else { - hash_extend_page(hash_ctx, (void*) fptr); - } +Error +Enclave::measureResidentArr(hash_ctx_t& hash_ctx, std::vector resident) { + char sub_hash[MDSIZE]; + hash_ctx_t file_hash_ctx; + for (resource_info_t& rInfo : resident) { + hash_extend(&hash_ctx, &rInfo.name, sizeof(rInfo.name)); + hash_extend(&hash_ctx, &rInfo.type, sizeof(rInfo.type)); + + // hash file + ElfFile elfFile(rInfo.filepath); + hash_init(&file_hash_ctx); + hash_extend(&file_hash_ctx, elfFile.getPtr(), elfFile.getFileSize()); + hash_finalize(sub_hash, &file_hash_ctx); + + // hash(file hash) + hash_extend(&hash_ctx, sub_hash, sizeof(sub_hash)); } + return Error::Success; } Error -Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath) { +Enclave::measureSelf(char* hash) { hash_ctx_t hash_ctx; hash_init(&hash_ctx); - ElfFile* loader = new ElfFile(loaderpath); - ElfFile* runtime = new ElfFile(runtimepath); - ElfFile* eapp = new ElfFile(eapppath); - - uintptr_t sizes[3] = { PAGE_UP(loader->getFileSize()), PAGE_UP(runtime->getFileSize()), - PAGE_UP(eapp->getFileSize()) }; - hash_extend(&hash_ctx, (void*) sizes, sizeof(sizes)); - - measureElfFile(&hash_ctx, *loader); - delete loader; - measureElfFile(&hash_ctx, *runtime); - delete runtime; - measureElfFile(&hash_ctx, *eapp); - delete eapp; + measureResidentArr(hash_ctx, identityResident); + for (resource_hash_t& rHash : identityAbsent) { + hash_extend(&hash_ctx, &rHash, sizeof(rHash)); + } + measureResidentArr(hash_ctx, resident); + for (resource_hash_t& rHash : absent) { + hash_extend(&hash_ctx, &rHash, sizeof(rHash)); + } hash_finalize(hash, &hash_ctx); + + return Error::Success; +} +Error +Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath) { + Enclave enclave; + Error err = Error::Success; + err = enclave.addResidentResource("loader", 0, loaderpath, true); + if (err != Error::Success) { + ERROR("failed to add loader with path %s", loaderpath); + return err; + } + err = enclave.addResidentResource("runtime", 0, runtimepath, true); + if (err != Error::Success) { + ERROR("failed to add runtime with path %s", loaderpath); + return err; + } + err = enclave.addResidentResource("eapp", 0, eapppath, true); + if (err != Error::Success) { + ERROR("failed to add eapp with path %s", loaderpath); + return err; + } + enclave.measureSelf(hash); return Error::Success; } @@ -134,17 +154,17 @@ Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, b uintptr_t Enclave::useEpm(uintptr_t src, uintptr_t size) { if (!size) { - return pDevice->getEpmVirtAddr() + epmFreeOffset; + return pDevice.getEpmVirtAddr() + epmFreeOffset; } uintptr_t allocatedOffset = epmFreeOffset; epmFreeOffset = PAGE_UP(epmFreeOffset + size); assert(epmFreeOffset > allocatedOffset); // no overflow - assert(epmFreeOffset <= pDevice->getEpmSize() - params.getFreeMemSize()); // free mem remaining - uintptr_t dest_va = pDevice->getEpmVirtAddr() + allocatedOffset; + assert(epmFreeOffset <= pDevice.getEpmSize() - params.getFreeMemSize()); // free mem remaining + uintptr_t dest_va = pDevice.getEpmVirtAddr() + allocatedOffset; if (src) { memcpy((void*) dest_va, (void*) src, size); uintptr_t end_va = dest_va + size; - memset((void*) end_va, 0, pDevice->getEpmVirtAddr() + epmFreeOffset - end_va); + memset((void*) end_va, 0, pDevice.getEpmVirtAddr() + epmFreeOffset - end_va); } return dest_va; } @@ -158,7 +178,7 @@ Enclave::materializeResourceInfo(resource_ptr_t residentResPtrs[], ElfFile* elfF resource_ptr_t* resPtr = residentResPtrs + i; strcpy(resPtr->name, resInfo.name); resPtr->type = resInfo.type; - resPtr->offset = useEpm((uintptr_t) elfFile->getPtr(), elfFile->getFileSize()) - pDevice->getEpmVirtAddr(); + resPtr->offset = useEpm((uintptr_t) elfFile->getPtr(), elfFile->getFileSize()) - pDevice.getEpmVirtAddr(); resPtr->size = (uintptr_t) elfFile->getFileSize(); } return Error::Success; @@ -171,10 +191,10 @@ Enclave::finalize() { // TODO(Evgeny): add comments to functions Error err = Error::Success; - pDevice = new KeystoneDevice(); + pDevice = KeystoneDevice(); epmFreeOffset = 0; - err = pDevice->initDevice(params); + err = pDevice.initDevice(params); if (err != Error::Success) { destroy(); return err; @@ -188,12 +208,12 @@ Enclave::finalize() { allElfFiles.push_back(new ElfFile(res_info.filepath)); } uint64_t requiredPages = calculateEpmPages(allElfFiles, params.getFreeMemSize()); - err = pDevice->create(requiredPages); + err = pDevice.create(requiredPages); if (err != Error::Success) { destroy(); return err; } - err = pDevice->initUTM(params.getUntrustedSize()); + err = pDevice.initUTM(params.getUntrustedSize()); if (err != Error::Success) { ERROR("failed to init untrusted memory - ioctl() failed"); destroy(); @@ -224,12 +244,12 @@ Enclave::finalize() { materializeResourceInfo((resource_ptr_t*) (ebase + ebundle_h->res_arr), &allElfFiles[identityResident.size()], resident); // finalize creating enclave - err = pDevice->finalize(epmFreeOffset); + err = pDevice.finalize(epmFreeOffset); if (err != Error::Success) { destroy(); return err; } - err = pDevice->mapUtm(); + err = pDevice.mapUtm(); if (err != Error::Success) { ERROR( "failed to finalize enclave - cannot obtain the untrusted buffer " @@ -273,20 +293,18 @@ Enclave::destroy() { delete elfFile; } allElfFiles.clear(); - Error err = pDevice->destroy(); - delete pDevice; - return err; + return pDevice.destroy(); } Error Enclave::run(uintptr_t* retval) { - Error ret = pDevice->run(retval); + Error ret = pDevice.run(retval); while (ret == Error::EdgeCallHost || ret == Error::EnclaveInterrupted) { /* enclave is stopped in the middle. */ if (ret == Error::EdgeCallHost && oFuncDispatch != NULL) { oFuncDispatch(getSharedBuffer()); } - ret = pDevice->resume(retval); + ret = pDevice.resume(retval); } if (ret != Error::Success) { @@ -300,14 +318,14 @@ Enclave::run(uintptr_t* retval) { void* Enclave::getSharedBuffer() { - assert(pDevice->getUtmVirtAddr()); - return (void*) pDevice->getUtmVirtAddr(); + assert(pDevice.getUtmVirtAddr()); + return (void*) pDevice.getUtmVirtAddr(); } size_t Enclave::getSharedBufferSize() { - assert(pDevice->getUtmSize()); - return pDevice->getUtmSize(); + assert(pDevice.getUtmSize()); + return pDevice.getUtmSize(); } Error diff --git a/sm/src/attest.c b/sm/src/attest.c index 1e503e730..b486dc869 100644 --- a/sm/src/attest.c +++ b/sm/src/attest.c @@ -53,6 +53,8 @@ int measure_resident_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t star } resource_ptr_t* elem = (resource_ptr_t*) (ebase + start_off); resource_ptr_t* end = (resource_ptr_t*) (ebase + end_off); + hash_ctx file_ctx; + char file_hash[MDSIZE]; for (; elem < end; elem++) { hash_extend(ctx, (char*) elem->name, sizeof(elem->name)); hash_extend(ctx, (char*) &elem->type, sizeof(elem->type)); @@ -60,7 +62,11 @@ int measure_resident_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t star || elem->offset + elem->size > efilled_size) { return 1; } - hash_extend(ctx, (char*) (ebase + elem->offset), elem->size); // TODO(Evgeny): is > page ok? + // hash file + hash_init(&file_ctx); + hash_extend(&file_ctx, (char*) (ebase + elem->offset), elem->size); + hash_finalize(file_hash, &file_ctx); + hash_extend(ctx, file_hash, sizeof(file_hash)); } return 0; } From 45662532922fa6eef856a198e1e285972a0daa17 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Tue, 26 Mar 2024 15:58:39 -0700 Subject: [PATCH 5/8] move elf discovery to inside enclave --- runtime/include/loader/loader.h | 2 + runtime/loader-binary/loader-binary.c | 18 ++++----- runtime/loader-binary/loader.S | 18 +++------ runtime/loader/loader.c | 16 +++++++- runtime/sys/boot.c | 20 ++++++---- sdk/include/host/Enclave.hpp | 1 + sdk/include/shared/sm_call.h | 7 ++-- sdk/src/host/Enclave.cpp | 54 +++++++++++++-------------- sm/src/attest.c | 25 ++++++------- sm/src/enclave.c | 18 ++++----- sm/src/enclave.h | 2 +- 11 files changed, 94 insertions(+), 87 deletions(-) diff --git a/runtime/include/loader/loader.h b/runtime/include/loader/loader.h index 2d3d19d0b..df5151f78 100644 --- a/runtime/include/loader/loader.h +++ b/runtime/include/loader/loader.h @@ -1,3 +1,5 @@ #include "loader/elf.h" +#include "sm_call.h" +resource_ptr_t* findIdentityResident(uintptr_t dram_base, const char* filename); int loadElf(elf_t* elf, bool user); diff --git a/runtime/loader-binary/loader-binary.c b/runtime/loader-binary/loader-binary.c index 0c0bd56b2..20d15046d 100644 --- a/runtime/loader-binary/loader-binary.c +++ b/runtime/loader-binary/loader-binary.c @@ -5,6 +5,7 @@ #include "mm/freemem.h" #include "util/printf.h" #include +#include "sm_call.h" /* root page table */ pte root_page_table_storage[BIT(RISCV_PT_INDEX_BITS)] __attribute__((aligned(RISCV_PAGE_SIZE))); @@ -40,9 +41,8 @@ int map_untrusted_memory(uintptr_t untrusted_ptr, uintptr_t untrusted_size) { } int load_runtime(uintptr_t dummy, - uintptr_t dram_base, uintptr_t dram_size, - uintptr_t runtime_base, uintptr_t user_base, - uintptr_t free_base, uintptr_t untrusted_ptr, + uintptr_t dram_base, uintptr_t dram_size, + uintptr_t free_base, uintptr_t untrusted_base, uintptr_t untrusted_size) { int ret = 0; @@ -51,15 +51,15 @@ int load_runtime(uintptr_t dummy, // initialize freemem spa_init(free_base, dram_base + dram_size - free_base); - // validate runtime elf - size_t runtime_size = user_base - runtime_base; - if (((void*) runtime_base == NULL) || (runtime_size <= 0)) { - return -1; + // find runtime + resource_ptr_t* runtime_ptr = findIdentityResident(dram_base, MSR_RUNTIME_FILENAME); + if (!runtime_ptr) { + return -1; } // create runtime elf struct elf_t runtime_elf; - ret = elf_newFile((void*) runtime_base, runtime_size, &runtime_elf); + ret = elf_newFile((void*) (dram_base + runtime_ptr->offset), runtime_ptr->size, &runtime_elf); if (ret != 0) { return ret; } @@ -74,7 +74,7 @@ int load_runtime(uintptr_t dummy, map_physical_memory(dram_base, dram_size); // map untrusted memory - ret = map_untrusted_memory(untrusted_ptr, untrusted_size); + ret = map_untrusted_memory(untrusted_base, untrusted_size); if (ret != 0) { return ret; } diff --git a/runtime/loader-binary/loader.S b/runtime/loader-binary/loader.S index 5908ffa73..7bf1339ad 100644 --- a/runtime/loader-binary/loader.S +++ b/runtime/loader-binary/loader.S @@ -7,24 +7,20 @@ _start: // a1: dram_base // a2: dram_size - // a3: runtime_base - // a4: user_base - // a5: free_base - // a6: untrusted_ptr - // a7: untrusted_size + // a3: free_base + // a4: untrusted_base + // a5: untrusted_size // use designated stack la sp, _estack // save all args to stack - addi sp, sp, -(REGBYTES*7) + addi sp, sp, -(REGBYTES*5) STORE a1, 0(sp) STORE a2, 1*REGBYTES(sp) STORE a3, 2*REGBYTES(sp) STORE a4, 3*REGBYTES(sp) STORE a5, 4*REGBYTES(sp) - STORE a6, 5*REGBYTES(sp) - STORE a7, 6*REGBYTES(sp) // call load_runtime call load_runtime @@ -52,11 +48,9 @@ _start: // set arguments for eyrie_boot LOAD a1, 0(sp) LOAD a2, 1*REGBYTES(sp) - LOAD a3, 2*REGBYTES(sp) + LOAD a3, free_base_final LOAD a4, 3*REGBYTES(sp) - LOAD a5, free_base_final - LOAD a6, 5*REGBYTES(sp) - LOAD a7, 6*REGBYTES(sp) + LOAD a5, 4*REGBYTES(sp) // flush TLB's just in case fence.i diff --git a/runtime/loader/loader.c b/runtime/loader/loader.c index f65a3aee0..a7b15bb00 100644 --- a/runtime/loader/loader.c +++ b/runtime/loader/loader.c @@ -6,6 +6,20 @@ #include "mm/vm_defs.h" #include "mm/vm.h" +resource_ptr_t* findIdentityResident(uintptr_t dram_base, const char* filename) { + // note: SM validates all pointers and sizes are within epm + enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) dram_base; + resource_ptr_t* id_res_resource = (resource_ptr_t*) (dram_base + ebundle_h->id_res_arr); + resource_ptr_t* id_abs_arr = (resource_ptr_t*) (dram_base + ebundle_h->id_abs_arr); + for (; id_res_resource < id_abs_arr; id_res_resource++) { + if (strcmp(id_res_resource->name, filename) == 0) { + return id_res_resource; + } + } + printf("findIdentityResident: filename \"%s\" not found\n", filename); + return 0; +} + static inline int pt_mode_from_elf(int elf_pt_mode) { return (((elf_pt_mode & PF_X) > 0) * PTE_X) | @@ -31,7 +45,7 @@ int loadElf(elf_t* elf, bool user) { /* va is not page-aligned, so it doesn't own some of the page. Page may already be mapped. */ if (RISCV_PAGE_OFFSET(va)) { if (RISCV_PAGE_OFFSET(va) != RISCV_PAGE_OFFSET((uintptr_t) src)) { - printf("loadElf: va and src are misaligned"); + printf("loadElf: va and src are misaligned\n"); return -1; } uintptr_t new_page = alloc_page(vpn(va), pt_mode); diff --git a/runtime/sys/boot.c b/runtime/sys/boot.c index 1310e3017..6cbfebac9 100644 --- a/runtime/sys/boot.c +++ b/runtime/sys/boot.c @@ -39,7 +39,7 @@ int verify_and_load_elf_file(uintptr_t ptr, size_t file_size, bool is_eapp) { } // parse and load elf file - ret = loadElf(&elf_file, 1); + ret = loadElf(&elf_file, is_eapp); if (is_eapp) { // setup entry point uintptr_t entry = elf_getEntryPoint(&elf_file); @@ -81,22 +81,28 @@ void eyrie_boot(uintptr_t dummy, // $a0 contains the return value from the SBI uintptr_t dram_base, uintptr_t dram_size, - uintptr_t runtime_paddr, - uintptr_t user_paddr, uintptr_t free_paddr, - uintptr_t utm_vaddr, + uintptr_t utm_paddr, uintptr_t utm_size) { + /* find runtime and eapp */ + resource_ptr_t* runtime_ptr = findIdentityResident(EYRIE_LOAD_START, MSR_RUNTIME_FILENAME); + resource_ptr_t* eapp_ptr = findIdentityResident(EYRIE_LOAD_START, MSR_EAPP_FILENAME); + assert(runtime_ptr); + assert(eapp_ptr); + /* set initial values */ - load_pa_start = dram_base; + load_pa_start = dram_base; // used by __va root_page_table = (pte*) __va(csr_read(satp) << RISCV_PAGE_BITS); shared_buffer = EYRIE_UNTRUSTED_START; shared_buffer_size = utm_size; runtime_va_start = (uintptr_t) &rt_base; + uintptr_t runtime_paddr = dram_base + runtime_ptr->offset; + uintptr_t user_paddr = dram_base + eapp_ptr->offset; kernel_offset = runtime_va_start - runtime_paddr; debug("ROOT PAGE TABLE: 0x%lx", root_page_table); - debug("UTM : 0x%lx-0x%lx (%u KB)", utm_vaddr, utm_vaddr+utm_size, utm_size/1024); + debug("UTM : 0x%lx-0x%lx (%u KB)", utm_paddr, utm_paddr+utm_size, utm_size/1024); debug("DRAM: 0x%lx-0x%lx (%u KB)", dram_base, dram_base + dram_size, dram_size/1024); debug("USER: 0x%lx-0x%lx (%u KB)", user_paddr, free_paddr, (free_paddr-user_paddr)/1024); @@ -111,7 +117,7 @@ eyrie_boot(uintptr_t dummy, // $a0 contains the return value from the SBI init_freemem(); /* load eapp elf */ - assert(!verify_and_load_elf_file(__va(user_paddr), free_paddr-user_paddr, true)); + assert(!verify_and_load_elf_file(__va(user_paddr), eapp_ptr->size, true)); /* free leaking memory */ // TODO: clean up after loader -- entire file no longer needed diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index fbffb7de8..d5a2768d9 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -49,6 +49,7 @@ class Enclave { std::vector absent; std::vector allElfFiles; + Error addStandard(const char* eapppath, const char* runtimepath, const char* loaderpath); static uint64_t calculateEpmPages(std::vector allElfFiles, size_t freeMemSize); // linearly advances as we write to epm uintptr_t epmFreeOffset; diff --git a/sdk/include/shared/sm_call.h b/sdk/include/shared/sm_call.h index 7e793a16d..bb1c8cda6 100644 --- a/sdk/include/shared/sm_call.h +++ b/sdk/include/shared/sm_call.h @@ -43,9 +43,7 @@ struct runtime_params_t { uintptr_t dram_base; uintptr_t dram_size; - uintptr_t loader_base; - uintptr_t runtime_base; - uintptr_t user_base; + uintptr_t start_pc; uintptr_t free_base; uintptr_t untrusted_base; uintptr_t untrusted_size; @@ -67,6 +65,9 @@ struct keystone_sbi_create_t { #define MSR_NAME_LEN 64 // #include "../common/sha3.h" // TODO(Evgeny): fix the include #define MDSIZE 64 +#define MSR_START_FILENAME "__0start" +#define MSR_RUNTIME_FILENAME "__1runtime" +#define MSR_EAPP_FILENAME "__2eapp" typedef struct { char name[MSR_NAME_LEN]; uintptr_t type; diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index e14857e0e..e52befd9d 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -93,20 +93,8 @@ Enclave::measureSelf(char* hash) { Error Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath) { Enclave enclave; - Error err = Error::Success; - err = enclave.addResidentResource("loader", 0, loaderpath, true); - if (err != Error::Success) { - ERROR("failed to add loader with path %s", loaderpath); - return err; - } - err = enclave.addResidentResource("runtime", 0, runtimepath, true); + Error err = enclave.addStandard(eapppath, runtimepath, loaderpath); if (err != Error::Success) { - ERROR("failed to add runtime with path %s", loaderpath); - return err; - } - err = enclave.addResidentResource("eapp", 0, eapppath, true); - if (err != Error::Success) { - ERROR("failed to add eapp with path %s", loaderpath); return err; } enclave.measureSelf(hash); @@ -151,6 +139,27 @@ Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, b return Error::Success; } +Error +Enclave::addStandard(const char* eapppath, const char* runtimepath, const char* loaderpath) { + Error err = Error::Success; + err = addResidentResource(MSR_START_FILENAME, 0, loaderpath, true); + if (err != Error::Success) { + ERROR("failed to add loader with path %s", loaderpath); + return err; + } + err = addResidentResource(MSR_RUNTIME_FILENAME, 0, runtimepath, true); + if (err != Error::Success) { + ERROR("failed to add runtime with path %s", loaderpath); + return err; + } + err = addResidentResource(MSR_EAPP_FILENAME, 0, eapppath, true); + if (err != Error::Success) { + ERROR("failed to add eapp with path %s", loaderpath); + return err; + } + return err; +} + uintptr_t Enclave::useEpm(uintptr_t src, uintptr_t size) { if (!size) { @@ -189,6 +198,7 @@ Enclave::finalize() { // TODO(Evgeny): ensure this is not called twice, no adds after, etc. // TODO(Evgeny): improve error messages // TODO(Evgeny): add comments to functions + // TODO(Evgeny): sort by filename Error err = Error::Success; pDevice = KeystoneDevice(); @@ -266,25 +276,11 @@ Error Enclave::init(const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params) { params = _params; - Error err = Error::Success; - err = addResidentResource("loader", 0, loaderpath, true); + Error err = addStandard(eapppath, runtimepath, loaderpath); if (err != Error::Success) { - ERROR("failed to add loader with path %s", loaderpath); return err; } - err = addResidentResource("runtime", 0, runtimepath, true); - if (err != Error::Success) { - ERROR("failed to add runtime with path %s", loaderpath); - return err; - } - err = addResidentResource("eapp", 0, eapppath, true); - if (err != Error::Success) { - ERROR("failed to add eapp with path %s", loaderpath); - return err; - } - err = finalize(); - - return err; + return finalize(); } Error diff --git a/sm/src/attest.c b/sm/src/attest.c index b486dc869..b33d30597 100644 --- a/sm/src/attest.c +++ b/sm/src/attest.c @@ -6,9 +6,9 @@ #include #include "page.h" #include -// #include +// #include // TODO(Evgeny): try to replace manual strcmp -int strcmp(const char* left, const char* right) { +static int strcmp(const char* left, const char* right) { for (; *left != '\0'; left++, right++) { if (*left != *right) { return (*left - *right); @@ -23,7 +23,7 @@ int strcmp(const char* left, const char* right) { return 0; } -int validate_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, uintptr_t elem_size) { +static int validate_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, uintptr_t elem_size) { uintptr_t start = ebase + start_off; uintptr_t end = ebase + end_off; if (start_off > end_off // bad loop condition @@ -35,7 +35,7 @@ int validate_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, u return 0; } -int measure_absent_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { +static int measure_absent_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { if(validate_arr(ebase, efilled_size, start_off, end_off, sizeof(resource_hash_t))) { return 1; } @@ -47,7 +47,7 @@ int measure_absent_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_ return 0; } -int measure_resident_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { +static int measure_resident_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { if(validate_arr(ebase, efilled_size, start_off, end_off, sizeof(resource_ptr_t))) { return 1; } @@ -71,7 +71,7 @@ int measure_resident_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t star return 0; } -int measure_runtime_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { +static int measure_runtime_arr(uintptr_t ebase, uintptr_t efilled_size, uintptr_t start_off, uintptr_t end_off, hash_ctx* ctx) { if(validate_arr(ebase, efilled_size, start_off, end_off, sizeof(runtime_val_t))) { return 1; } @@ -111,16 +111,13 @@ unsigned long validate_and_hash_enclave(struct enclave* enclave){ resource_ptr_t* id_abs_arr = (resource_ptr_t*) (ebase + ebundle_h->id_abs_arr); // note: no overflow/ out of bounds possible because measure_resident_arr would have failed for (; id_res_resource < id_abs_arr; id_res_resource++) { - if (strcmp(id_res_resource->name, "loader") == 0) { - enclave->params.loader_base = ebase + id_res_resource->offset; - } else if (strcmp(id_res_resource->name, "runtime") == 0) { - enclave->params.runtime_base = ebase + id_res_resource->offset; - } else if (strcmp(id_res_resource->name, "eapp") == 0) { - enclave->params.user_base = ebase + id_res_resource->offset; + if (strcmp(id_res_resource->name, MSR_START_FILENAME) == 0) { + enclave->params.start_pc = ebase + id_res_resource->offset; + break; } } - if (!enclave->params.loader_base || !enclave->params.runtime_base || !enclave->params.user_base) { - return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; // TODO(Evgeny): incorrect error type + if (!enclave->params.start_pc) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; } return SBI_ERR_SM_ENCLAVE_SUCCESS; diff --git a/sm/src/enclave.c b/sm/src/enclave.c index 1ebc387cc..9ebc58c7f 100644 --- a/sm/src/enclave.c +++ b/sm/src/enclave.c @@ -52,22 +52,18 @@ static inline void context_switch_to_enclave(struct sbi_trap_regs* regs, if(load_parameters) { // passing parameters for a first run - regs->mepc = (uintptr_t) enclaves[eid].params.loader_base - 4; // regs->mepc will be +4 before sbi_ecall_handler return + regs->mepc = (uintptr_t) enclaves[eid].params.start_pc - 4; // regs->mepc will be +4 before sbi_ecall_handler return regs->mstatus = (1 << MSTATUS_MPP_SHIFT); // $a1: (PA) DRAM base, regs->a1 = (uintptr_t) enclaves[eid].params.dram_base; // $a2: DRAM size, regs->a2 = (uintptr_t) enclaves[eid].params.dram_size; - // $a3: (PA) kernel location, - regs->a3 = (uintptr_t) enclaves[eid].params.runtime_base; - // $a4: (PA) user location, - regs->a4 = (uintptr_t) enclaves[eid].params.user_base; - // $a5: (PA) freemem location, - regs->a5 = (uintptr_t) enclaves[eid].params.free_base; - // $a6: (PA) utm base, - regs->a6 = (uintptr_t) enclaves[eid].params.untrusted_base; - // $a7: utm size - regs->a7 = (uintptr_t) enclaves[eid].params.untrusted_size; + // $a3: (PA) freemem base, + regs->a3 = (uintptr_t) enclaves[eid].params.free_base; + // $a4: (PA) utm base, + regs->a4 = (uintptr_t) enclaves[eid].params.untrusted_base; + // $a5: utm size + regs->a5 = (uintptr_t) enclaves[eid].params.untrusted_size; // enclave will only have physical addresses in the first run csr_write(satp, 0); diff --git a/sm/src/enclave.h b/sm/src/enclave.h index 09024d0ee..ac38f606f 100644 --- a/sm/src/enclave.h +++ b/sm/src/enclave.h @@ -117,7 +117,7 @@ unsigned long resume_enclave(struct sbi_trap_regs *regs, enclave_id eid); unsigned long exit_enclave(struct sbi_trap_regs *regs, enclave_id eid); unsigned long stop_enclave(struct sbi_trap_regs *regs, uint64_t request, enclave_id eid); unsigned long attest_enclave(uintptr_t report, uintptr_t data, uintptr_t size, enclave_id eid); -// attestation +// attestation. validates that all pointers and sizes are inside epm unsigned long validate_and_hash_enclave(struct enclave* enclave); // TODO: These functions are supposed to be internal functions. void enclave_init_metadata(void); From b49b3be3221903383030f4ec38cecae507fb2572 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Tue, 26 Mar 2024 17:19:31 -0700 Subject: [PATCH 6/8] add memory sizes to attest hash --- examples/attestation/host/verifier.cpp | 2 +- sdk/include/host/Enclave.hpp | 2 +- sdk/include/shared/sm_call.h | 4 +++- sdk/src/host/Enclave.cpp | 20 ++++++++++++++----- sm/src/attest.c | 27 ++++++++++++++++++++------ 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/examples/attestation/host/verifier.cpp b/examples/attestation/host/verifier.cpp index b90fe7168..ec5574cc4 100644 --- a/examples/attestation/host/verifier.cpp +++ b/examples/attestation/host/verifier.cpp @@ -78,7 +78,7 @@ Verifier::verify_data(Report& report, const std::string& nonce) { void Verifier::compute_expected_enclave_hash(byte* expected_enclave_hash) { - Keystone::Enclave::measure((char*) expected_enclave_hash, eapp_file_.c_str(), rt_file_.c_str(), ld_file_.c_str()); + Keystone::Enclave::measure((char*) expected_enclave_hash, eapp_file_.c_str(), rt_file_.c_str(), ld_file_.c_str(), params_); } void diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index d5a2768d9..04aafdfa2 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -66,7 +66,7 @@ class Enclave { Enclave(); ~Enclave(); Error measureSelf(char* hash); - static Error measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath); + static Error measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath, Params params); // shared buffer is utm void* getSharedBuffer(); size_t getSharedBufferSize(); diff --git a/sdk/include/shared/sm_call.h b/sdk/include/shared/sm_call.h index bb1c8cda6..64690b078 100644 --- a/sdk/include/shared/sm_call.h +++ b/sdk/include/shared/sm_call.h @@ -68,6 +68,8 @@ struct keystone_sbi_create_t { #define MSR_START_FILENAME "__0start" #define MSR_RUNTIME_FILENAME "__1runtime" #define MSR_EAPP_FILENAME "__2eapp" +#define MSR_FREE_MEM "free_mem" +#define MSR_UT_MEM "ut_mem" typedef struct { char name[MSR_NAME_LEN]; uintptr_t type; @@ -89,7 +91,7 @@ typedef struct { // TODO(Evgeny): a way to make this more convenient? should I make the pointers typed? typedef struct { uintptr_t runtime_arr, id_res_arr, - id_abs_arr, res_arr, abs_arr, data; + id_abs_arr, res_arr, abs_arr, pad_start; // resource_value_t runtime_values[]; // resource_ptr_t identity_resident[]; // resource_hash_t identity_absent[]; diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index e52befd9d..84ae5ea43 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -76,6 +76,12 @@ Enclave::measureSelf(char* hash) { hash_ctx_t hash_ctx; hash_init(&hash_ctx); + // runtime vals + runtime_val_t runtime_val = {.name = MSR_FREE_MEM, .val = params.getFreeMemSize()}; + hash_extend(&hash_ctx, &runtime_val, sizeof(runtime_val)); + runtime_val = {.name = MSR_UT_MEM, .val = params.getUntrustedSize()}; + hash_extend(&hash_ctx, &runtime_val, sizeof(runtime_val)); + measureResidentArr(hash_ctx, identityResident); for (resource_hash_t& rHash : identityAbsent) { hash_extend(&hash_ctx, &rHash, sizeof(rHash)); @@ -91,8 +97,9 @@ Enclave::measureSelf(char* hash) { } Error -Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath) { +Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath, Params params) { Enclave enclave; + enclave.params = params; Error err = enclave.addStandard(eapppath, runtimepath, loaderpath); if (err != Error::Success) { return err; @@ -235,19 +242,22 @@ Enclave::finalize() { // space out the arrays ebundle_h->runtime_arr = (uintptr_t) sizeof(enclave_bundle_header_t); - ebundle_h->id_res_arr = ebundle_h->runtime_arr + 0; // TODO(Evgeny) + ebundle_h->id_res_arr = ebundle_h->runtime_arr + + (uintptr_t) (sizeof(runtime_val_t) * 2); ebundle_h->id_abs_arr = ebundle_h->id_res_arr + (uintptr_t) (sizeof(resource_ptr_t) * identityResident.size()); ebundle_h->res_arr = ebundle_h->id_abs_arr + (uintptr_t) (sizeof(resource_hash_t) * identityAbsent.size()); ebundle_h->abs_arr = ebundle_h->res_arr + (uintptr_t) (sizeof(resource_ptr_t) * resident.size()); - ebundle_h->data = ebundle_h->abs_arr + ebundle_h->pad_start = ebundle_h->abs_arr + (uintptr_t) (sizeof(resource_hash_t) * absent.size()); - useEpm(0, ebundle_h->data); // contiguous ebundle_h and arrays, then page padding + useEpm(0, ebundle_h->pad_start); // contiguous ebundle_h and arrays, then page padding // fill in the arrays & data - // TODO(Evgeny): runtime values + runtime_val_t* runtime_arr = (runtime_val_t*) (ebase + ebundle_h->runtime_arr); + runtime_arr[0] = {.name = MSR_FREE_MEM, .val = params.getFreeMemSize()}; + runtime_arr[1] = {.name = MSR_UT_MEM, .val = params.getUntrustedSize()}; memcpy((void*) (ebase + ebundle_h->id_abs_arr), &identityAbsent[0], sizeof(resource_hash_t) * identityAbsent.size()); memcpy((void*) (ebase + ebundle_h->abs_arr), &absent[0], sizeof(resource_hash_t) * absent.size()); materializeResourceInfo((resource_ptr_t*) (ebase + ebundle_h->id_res_arr), &allElfFiles[0], identityResident); diff --git a/sm/src/attest.c b/sm/src/attest.c index b33d30597..d78f73a5b 100644 --- a/sm/src/attest.c +++ b/sm/src/attest.c @@ -88,8 +88,6 @@ unsigned long validate_and_hash_enclave(struct enclave* enclave){ enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) ebase; uintptr_t efilled_size = enclave->params.free_base - ebase; - // TODO(Evgeny): ensure untrusted and free sizes - // hash the epm contents hash_ctx ctx; hash_init(&ctx); @@ -98,16 +96,30 @@ unsigned long validate_and_hash_enclave(struct enclave* enclave){ fail_state |= measure_resident_arr(ebase, efilled_size, ebundle_h->id_res_arr, ebundle_h->id_abs_arr, &ctx); fail_state |= measure_absent_arr(ebase, efilled_size, ebundle_h->id_abs_arr, ebundle_h->res_arr, &ctx); hash_ctx ctx_copy = ctx; - hash_finalize(enclave->identity, &ctx_copy); fail_state |= measure_resident_arr(ebase, efilled_size, ebundle_h->res_arr, ebundle_h->abs_arr, &ctx); - fail_state |= measure_absent_arr(ebase, efilled_size, ebundle_h->abs_arr, ebundle_h->data, &ctx); + fail_state |= measure_absent_arr(ebase, efilled_size, ebundle_h->abs_arr, ebundle_h->pad_start, &ctx); if (fail_state) { return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; } - hash_finalize(enclave->hash, &ctx); - // TODO(Evgeny): move discovery into enclave + // confirm the runtime value claims + runtime_val_t* runtime_val = (runtime_val_t*) (ebase + ebundle_h->runtime_arr); resource_ptr_t* id_res_resource = (resource_ptr_t*) (ebase + ebundle_h->id_res_arr); + for (; runtime_val < (runtime_val_t*) id_res_resource; runtime_val++) { + if (strcmp(runtime_val->name, MSR_FREE_MEM) == 0) { + if (runtime_val->val > enclave->params.dram_size - enclave->params.free_base) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; + } + } else if (strcmp(runtime_val->name, MSR_UT_MEM) == 0) { + if (runtime_val->val != enclave->params.untrusted_size) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; + } + } else { + // claim unsupported by platform + return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; + } + } + resource_ptr_t* id_abs_arr = (resource_ptr_t*) (ebase + ebundle_h->id_abs_arr); // note: no overflow/ out of bounds possible because measure_resident_arr would have failed for (; id_res_resource < id_abs_arr; id_res_resource++) { @@ -120,5 +132,8 @@ unsigned long validate_and_hash_enclave(struct enclave* enclave){ return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; } + hash_finalize(enclave->identity, &ctx_copy); // TODO(Evgeny): use identity for sealing key derivation + hash_finalize(enclave->hash, &ctx); + return SBI_ERR_SM_ENCLAVE_SUCCESS; } From 2a5afeb01f378b009dc8a40bd01f85f0c9b6a246 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Tue, 26 Mar 2024 17:24:20 -0700 Subject: [PATCH 7/8] rename init to finalize --- examples/attestation/host/host.cpp | 2 +- examples/hello-native/host/host_native.cpp | 2 +- examples/hello/host/host.cpp | 2 +- examples/tests/test-runner.cpp | 2 +- sdk/include/host/Enclave.hpp | 4 ++-- sdk/src/host/Enclave.cpp | 5 ++++- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/attestation/host/host.cpp b/examples/attestation/host/host.cpp index b121ac59a..8acc4c57d 100644 --- a/examples/attestation/host/host.cpp +++ b/examples/attestation/host/host.cpp @@ -235,7 +235,7 @@ Host::dispatch_ocall(RunData& run_data) { Report Host::run(const std::string& nonce) { Keystone::Enclave enclave; - enclave.init(eapp_file_.c_str(), rt_file_.c_str(), ld_file_.c_str(), params_); + enclave.finalize(eapp_file_.c_str(), rt_file_.c_str(), ld_file_.c_str(), params_); RunData run_data{ SharedBuffer{enclave.getSharedBuffer(), enclave.getSharedBufferSize()}, diff --git a/examples/hello-native/host/host_native.cpp b/examples/hello-native/host/host_native.cpp index 875c82e43..489291c13 100644 --- a/examples/hello-native/host/host_native.cpp +++ b/examples/hello-native/host/host_native.cpp @@ -30,7 +30,7 @@ main(int argc, char** argv) { params.setFreeMemSize(1024 * 1024); params.setUntrustedSize(1024 * 1024); - enclave.init(argv[1], argv[2], argv[3], params); + enclave.finalize(argv[1], argv[2], argv[3], params); enclave.registerOcallDispatch(incoming_call_dispatch); diff --git a/examples/hello/host/host.cpp b/examples/hello/host/host.cpp index 0b9db90fd..ca453182c 100644 --- a/examples/hello/host/host.cpp +++ b/examples/hello/host/host.cpp @@ -15,7 +15,7 @@ main(int argc, char** argv) { params.setFreeMemSize(256 * 1024); params.setUntrustedSize(256 * 1024); - enclave.init(argv[1], argv[2], argv[3], params); + enclave.finalize(argv[1], argv[2], argv[3], params); enclave.registerOcallDispatch(incoming_call_dispatch); edge_call_init_internals( diff --git a/examples/tests/test-runner.cpp b/examples/tests/test-runner.cpp index 29ea7e228..efb1497b0 100644 --- a/examples/tests/test-runner.cpp +++ b/examples/tests/test-runner.cpp @@ -117,7 +117,7 @@ main(int argc, char** argv) { asm volatile("rdcycle %0" : "=r"(cycles1)); } - enclave.init(eapp_file, rt_file, ld_file, params); + enclave.finalize(eapp_file, rt_file, ld_file, params); if (self_timing) { asm volatile("rdcycle %0" : "=r"(cycles2)); diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index 04aafdfa2..ee05a5aee 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -64,6 +64,7 @@ class Enclave { public: Enclave(); + Enclave(Params params); ~Enclave(); Error measureSelf(char* hash); static Error measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath, Params params); @@ -71,8 +72,7 @@ class Enclave { void* getSharedBuffer(); size_t getSharedBufferSize(); Error registerOcallDispatch(OcallFunc func); - // TODO(Evgeny): rename init to something else. finalize? - Error init(const char* filepath, const char* runtime, const char* loaderpath, Params parameters); + Error finalize(const char* filepath, const char* runtime, const char* loaderpath, Params _params); Error destroy(); Error run(uintptr_t* ret = nullptr); diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index 84ae5ea43..dd08df49b 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -17,6 +17,9 @@ namespace Keystone { Enclave::Enclave() { } +Enclave::Enclave(Params params) : params(params) { +} + Enclave::~Enclave() { assert(destroy() == Error::Success); } @@ -283,7 +286,7 @@ Enclave::finalize() { } Error -Enclave::init(const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params) { +Enclave::finalize(const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params) { params = _params; Error err = addStandard(eapppath, runtimepath, loaderpath); From 997be310bdbdc0e9faf5f6e5fa959c2ea1f09919 Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Tue, 26 Mar 2024 17:55:09 -0700 Subject: [PATCH 8/8] sort resources, minor fixes --- sdk/include/host/Enclave.hpp | 7 +++-- sdk/include/shared/sm_call.h | 6 ++--- sdk/src/host/Enclave.cpp | 51 ++++++++++++++++++++++++++++-------- sm/src/attest.c | 2 +- sm/src/enclave.c | 2 +- 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index ee05a5aee..bcb7a5b45 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -49,7 +49,6 @@ class Enclave { std::vector absent; std::vector allElfFiles; - Error addStandard(const char* eapppath, const char* runtimepath, const char* loaderpath); static uint64_t calculateEpmPages(std::vector allElfFiles, size_t freeMemSize); // linearly advances as we write to epm uintptr_t epmFreeOffset; @@ -61,6 +60,9 @@ class Enclave { Error materializeResourceInfo(resource_ptr_t residentResPtrs[], ElfFile* allElfFiles[], std::vector resInfos); static Error measureResidentArr(hash_ctx_t& hash_ctx, std::vector resident); + static bool resourceInfoCompare(const resource_info_t& a, const resource_info_t& b); + static bool resourceHashCompare(const resource_hash_t& a, const resource_hash_t& b); + void sortAllResources(); public: Enclave(); @@ -72,14 +74,15 @@ class Enclave { void* getSharedBuffer(); size_t getSharedBufferSize(); Error registerOcallDispatch(OcallFunc func); - Error finalize(const char* filepath, const char* runtime, const char* loaderpath, Params _params); Error destroy(); Error run(uintptr_t* ret = nullptr); Error addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity); Error addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity); + Error addStandard(const char* eapppath, const char* runtimepath, const char* loaderpath); // Call after adding all needed resources to fully create the enclave. Error finalize(); + Error finalize(const char* filepath, const char* runtime, const char* loaderpath, Params _params); }; } // namespace Keystone diff --git a/sdk/include/shared/sm_call.h b/sdk/include/shared/sm_call.h index 64690b078..614eeec9b 100644 --- a/sdk/include/shared/sm_call.h +++ b/sdk/include/shared/sm_call.h @@ -63,7 +63,7 @@ struct keystone_sbi_create_t { // TODO(Evgeny): how do we ensure no compiler re-ordering? #define MSR_NAME_LEN 64 -// #include "../common/sha3.h" // TODO(Evgeny): fix the include +// #include "common/sha3.h" // TODO(Evgeny): fix the include #define MDSIZE 64 #define MSR_START_FILENAME "__0start" #define MSR_RUNTIME_FILENAME "__1runtime" @@ -88,7 +88,7 @@ typedef struct { uintptr_t val; } runtime_val_t; -// TODO(Evgeny): a way to make this more convenient? should I make the pointers typed? +// TODO(Evgeny): a way to make this more convenient? typedef struct { uintptr_t runtime_arr, id_res_arr, id_abs_arr, res_arr, abs_arr, pad_start; @@ -97,7 +97,7 @@ typedef struct { // resource_hash_t identity_absent[]; // resource_ptr_t resident[]; // resource_hash_t absent[]; - // byte data[]; + // byte pad_start[]; } enclave_bundle_header_t; #endif // __SM_CALL_H__ diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index dd08df49b..87eb71978 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -76,6 +76,8 @@ Enclave::measureResidentArr(hash_ctx_t& hash_ctx, std::vector r Error Enclave::measureSelf(char* hash) { + sortAllResources(); + hash_ctx_t hash_ctx; hash_init(&hash_ctx); @@ -203,12 +205,40 @@ Enclave::materializeResourceInfo(resource_ptr_t residentResPtrs[], ElfFile* elfF return Error::Success; } +bool +Enclave::resourceInfoCompare(const resource_info_t& a, const resource_info_t& b) { + return strcmp(a.name, b.name) < 0; +} + +bool +Enclave::resourceHashCompare(const resource_hash_t& a, const resource_hash_t& b) { + return strcmp(a.name, b.name) < 0; +} + +void +Enclave::sortAllResources() { + // sort by filename + std::sort(identityResident.begin(), identityResident.end(), resourceInfoCompare); + std::sort(identityAbsent.begin(), identityAbsent.end(), resourceHashCompare); + std::sort(resident.begin(), resident.end(), resourceInfoCompare); + std::sort(absent.begin(), absent.end(), resourceHashCompare); +} + Error Enclave::finalize() { - // TODO(Evgeny): ensure this is not called twice, no adds after, etc. - // TODO(Evgeny): improve error messages - // TODO(Evgeny): add comments to functions - // TODO(Evgeny): sort by filename + sortAllResources(); + + // confirm start executable is present + bool startExecutablePresent = false; + for (const resource_info_t& resInfo : identityResident) { + if (strcmp(resInfo.name, MSR_START_FILENAME) == 0) { + startExecutablePresent = true; + break; + } + } + if (!startExecutablePresent) { + return Error::BadArgument; + } Error err = Error::Success; pDevice = KeystoneDevice(); @@ -221,11 +251,11 @@ Enclave::finalize() { } // allocate enclave memory - for (const resource_info_t& res_info : identityResident) { - allElfFiles.push_back(new ElfFile(res_info.filepath)); + for (const resource_info_t& resInfo : identityResident) { + allElfFiles.push_back(new ElfFile(resInfo.filepath)); } - for (const resource_info_t& res_info : resident) { - allElfFiles.push_back(new ElfFile(res_info.filepath)); + for (const resource_info_t& resInfo : resident) { + allElfFiles.push_back(new ElfFile(resInfo.filepath)); } uint64_t requiredPages = calculateEpmPages(allElfFiles, params.getFreeMemSize()); err = pDevice.create(requiredPages); @@ -257,7 +287,7 @@ Enclave::finalize() { + (uintptr_t) (sizeof(resource_hash_t) * absent.size()); useEpm(0, ebundle_h->pad_start); // contiguous ebundle_h and arrays, then page padding - // fill in the arrays & data + // fill in the arrays and copy files runtime_val_t* runtime_arr = (runtime_val_t*) (ebase + ebundle_h->runtime_arr); runtime_arr[0] = {.name = MSR_FREE_MEM, .val = params.getFreeMemSize()}; runtime_arr[1] = {.name = MSR_UT_MEM, .val = params.getUntrustedSize()}; @@ -275,13 +305,12 @@ Enclave::finalize() { err = pDevice.mapUtm(); if (err != Error::Success) { ERROR( - "failed to finalize enclave - cannot obtain the untrusted buffer " + "failed to finalize enclave - cannot map the untrusted buffer " "pointer \n"); destroy(); return err; } - // TODO(Evgeny): validate that loader is present return Error::Success; } diff --git a/sm/src/attest.c b/sm/src/attest.c index d78f73a5b..70146d817 100644 --- a/sm/src/attest.c +++ b/sm/src/attest.c @@ -132,7 +132,7 @@ unsigned long validate_and_hash_enclave(struct enclave* enclave){ return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; } - hash_finalize(enclave->identity, &ctx_copy); // TODO(Evgeny): use identity for sealing key derivation + hash_finalize(enclave->identity, &ctx_copy); hash_finalize(enclave->hash, &ctx); return SBI_ERR_SM_ENCLAVE_SUCCESS; diff --git a/sm/src/enclave.c b/sm/src/enclave.c index 9ebc58c7f..b2308f795 100644 --- a/sm/src/enclave.c +++ b/sm/src/enclave.c @@ -650,7 +650,7 @@ unsigned long get_sealing_key(uintptr_t sealing_key, uintptr_t key_ident, /* derive key */ ret = sm_derive_sealing_key((unsigned char *)key_struct->key, (const unsigned char *)key_ident, key_ident_size, - (const unsigned char *)enclaves[eid].hash); + (const unsigned char *)enclaves[eid].identity); if (ret) return SBI_ERR_SM_ENCLAVE_UNKNOWN_ERROR;