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/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/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/linux-keystone-driver/keystone-ioctl.c b/linux-keystone-driver/keystone-ioctl.c index 08a50359a..9b88b37fc 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_offset = enclp->free_offset; utm = enclave->utm; @@ -67,16 +68,10 @@ 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) { - 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/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/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 57e571754..bcb7a5b45 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" { @@ -23,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 { @@ -33,42 +34,55 @@ 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; + KeystoneDevice pDevice; OcallFunc oFuncDispatch; - bool mapUntrusted(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; + std::string filepath; + } resource_info_t; + std::vector identityResident; + std::vector identityAbsent; + std::vector resident; + std::vector absent; + 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 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(); + Enclave(Params params); ~Enclave(); - static Error measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath); + Error measureSelf(char* hash); + 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(); - Memory* getMemory(); - uintptr_t getRuntimeElfAddr() { return runtimeElfAddr; } - uintptr_t getEnclaveElfAddr() { return enclaveElfAddr; } Error registerOcallDispatch(OcallFunc func); - 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); -}; -uint64_t -calculate_required_pages(ElfFile** elfFiles, size_t numElfFiles); + 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/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 d08d76d92..90e0857ba 100644 --- a/sdk/include/host/KeystoneDevice.hpp +++ b/sdk/include/host/KeystoneDevice.hpp @@ -25,48 +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 runtimePhysAddr, uintptr_t eappPhysAddr, uintptr_t freePhysAddr, - uintptr_t freeRequested); + 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 203c82ed3..000000000 --- a/sdk/include/host/Memory.hpp +++ /dev/null @@ -1,93 +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; - - // 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/include/shared/keystone_user.h b/sdk/include/shared/keystone_user.h index 585709cc9..a4cbb9b31 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_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 b9d8f959a..614eeec9b 100644 --- a/sdk/include/shared/sm_call.h +++ b/sdk/include/shared/sm_call.h @@ -43,8 +43,7 @@ struct runtime_params_t { uintptr_t dram_base; uintptr_t dram_size; - uintptr_t runtime_base; - uintptr_t user_base; + uintptr_t start_pc; uintptr_t free_base; uintptr_t untrusted_base; uintptr_t untrusted_size; @@ -59,11 +58,46 @@ 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; + 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 +#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; + 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; + +typedef struct { + char name[MSR_NAME_LEN]; + uintptr_t val; +} runtime_val_t; + +// 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; + // resource_value_t runtime_values[]; + // resource_ptr_t identity_resident[]; + // resource_hash_t identity_absent[]; + // resource_ptr_t resident[]; + // resource_hash_t absent[]; + // byte pad_start[]; +} enclave_bundle_header_t; + #endif // __SM_CALL_H__ 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 8316a9da9..87eb71978 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -11,24 +11,25 @@ extern "C" { #include "shared/keystone_user.h" } #include "ElfFile.hpp" -#include "hash_util.hpp" namespace Keystone { Enclave::Enclave() { } +Enclave::Enclave(Params params) : params(params) { +} + Enclave::~Enclave() { - destroy(); + assert(destroy() == Error::Success); } 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,202 +46,303 @@ 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; + pages += PAGE_UP(freeMemSize) / PAGE_SIZE; + return pages; +} - /* Call Enclave Driver */ - if (pDevice->create(minPages) != Error::Success) { - return false; +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; +} - /* We switch out the phys addr as needed */ - uintptr_t physAddr; - if (alternatePhysAddr) { - physAddr = alternatePhysAddr; - } else { - physAddr = pDevice->getPhysAddr(); +Error +Enclave::measureSelf(char* hash) { + sortAllResources(); + + 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)); + } + measureResidentArr(hash_ctx, resident); + for (resource_hash_t& rHash : absent) { + hash_extend(&hash_ctx, &rHash, sizeof(rHash)); } - pMemory->init(pDevice, physAddr, minPages); - return true; + hash_finalize(hash, &hash_ctx); + + return Error::Success; } -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; - } +Error +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; + } + enclave.measureSelf(hash); + return Error::Success; } -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(); - - 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::addResidentResource(const char* name, uintptr_t type, const char* filepath, bool identity) { + if (strlen(name) >= MSR_NAME_LEN) { + return Error::BadArgument; } + 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 Error::Success; } Error -Enclave::measure(char* hash, const char* eapppath, const char* runtimepath, const char* loaderpath) { - 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)); +Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, bool identity) { + if (strlen(name) >= MSR_NAME_LEN) { + return Error::BadArgument; + } + 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 Error::Success; +} - measureElfFile(&hash_ctx, loader); - delete loader; - measureElfFile(&hash_ctx, runtime); - delete runtime; - measureElfFile(&hash_ctx, eapp); - delete eapp; +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; +} - hash_finalize(hash, &hash_ctx); +uintptr_t +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]; + ElfFile* elfFile = elfFiles[i]; + 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->size = (uintptr_t) elfFile->getFileSize(); + } 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); +bool +Enclave::resourceInfoCompare(const resource_info_t& a, const resource_info_t& b) { + return strcmp(a.name, b.name) < 0; } -Error -Enclave::init( - const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params, - uintptr_t alternatePhysAddr) { - params = _params; +bool +Enclave::resourceHashCompare(const resource_hash_t& a, const resource_hash_t& b) { + return strcmp(a.name, b.name) < 0; +} - pMemory = new PhysicalEnclaveMemory(); - pDevice = new KeystoneDevice(); +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); +} - ElfFile* enclaveFile = new ElfFile(eapppath); - ElfFile* runtimeFile = new ElfFile(runtimepath); - ElfFile* loaderFile = new ElfFile(loaderpath); +Error +Enclave::finalize() { + 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(); + epmFreeOffset = 0; - if (!pDevice->initDevice(params)) { + err = pDevice.initDevice(params); + if (err != Error::Success) { destroy(); - return Error::DeviceInitFailure; + return err; } - ElfFile* elfFiles[3] = {enclaveFile, runtimeFile, loaderFile}; - size_t requiredPages = calculate_required_pages(elfFiles, 3); - - if (!prepareEnclaveMemory(requiredPages, alternatePhysAddr)) { + // allocate enclave memory + for (const resource_info_t& resInfo : identityResident) { + allElfFiles.push_back(new ElfFile(resInfo.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); + if (err != Error::Success) { destroy(); - 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 Error::DeviceError; + return err; } - - /* 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) { + 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); + 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->pad_start = ebundle_h->abs_arr + + (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 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()}; + 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 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 " + "failed to finalize enclave - cannot map the untrusted buffer " "pointer \n"); destroy(); - return Error::DeviceMemoryMapError; + return err; } - /* ELF files are no longer needed */ - delete enclaveFile; - delete runtimeFile; - delete loaderFile; return Error::Success; } -bool -Enclave::mapUntrusted(size_t size) { - if (size == 0) { - return true; - } - - shared_buffer = pDevice->map(0, size); +Error +Enclave::finalize(const char* eapppath, const char* runtimepath, const char* loaderpath, Params _params) { + params = _params; - if (shared_buffer == NULL) { - return false; + Error err = addStandard(eapppath, runtimepath, loaderpath); + if (err != Error::Success) { + return err; } - - shared_buffer_size = size; - - return true; + return finalize(); } Error Enclave::destroy() { - return pDevice->destroy(); + for (ElfFile* elfFile : allElfFiles) { + delete elfFile; + } + allElfFiles.clear(); + 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) { @@ -254,17 +356,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 42e8d4c4c..15edcb525 100644 --- a/sdk/src/host/KeystoneDevice.cpp +++ b/sdk/src/host/KeystoneDevice.cpp @@ -20,39 +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 runtimePhysAddr, uintptr_t eappPhysAddr, uintptr_t freePhysAddr, - uintptr_t freeRequested) { +KeystoneDevice::finalize(uintptr_t freeOffset) { 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_offset = freeOffset; if (ioctl(fd, KEYSTONE_IOC_FINALIZE_ENCLAVE, &encl)) { perror("ioctl error"); return Error::IoctlErrorFinalize; } + finalizeDone = true; return Error::Success; } @@ -122,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 ed95d8674..000000000 --- a/sdk/src/host/PhysicalEnclaveMemory.cpp +++ /dev/null @@ -1,58 +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; - // TODO(dayeol): need to set actual EPM size - epmSize = PAGE_SIZE * min_pages; - epmFreeList = 0; - startAddr = phys_addr; -} - -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); - void* va_dst = pDevice->map(offset, size); - memcpy(va_dst, 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) diff --git a/sm/src/attest.c b/sm/src/attest.c index cdef976da..70146d817 100644 --- a/sm/src/attest.c +++ b/sm/src/attest.c @@ -6,46 +6,133 @@ #include #include "page.h" #include +// #include // TODO(Evgeny): try to replace manual strcmp -/* 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; +static 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; +} - // 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)); +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 + || end_off > efilled_size // out of bounds reads + || ebase >= start || ebase >= end // overflow + || (end - start) % elem_size != 0 ) { // hanging read + return 1; + } + return 0; +} - // 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); +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; + } + 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(ctx, (void*) elem, sizeof(resource_hash_t)); } - for (uintptr_t page = runtime; page < eapp; page += RISCV_PGSIZE) { - hash_extend_page(ctx, (void*) page); + return 0; +} + +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; } - for (uintptr_t page = eapp; page < free; page += RISCV_PGSIZE) { - hash_extend_page(ctx, (void*) page); + 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)); + if (elem->offset >= elem->offset + elem->size + || elem->offset + elem->size > efilled_size) { + return 1; + } + // 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; +} + +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; + } + 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){ + uintptr_t ebase = enclave->params.dram_base; + enclave_bundle_header_t* ebundle_h = (enclave_bundle_header_t*) ebase; + uintptr_t efilled_size = enclave->params.free_base - ebase; + + // hash the epm contents hash_ctx ctx; hash_init(&ctx); + bool fail_state = 0; + 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; + 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->pad_start, &ctx); + if (fail_state) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; + } - // TODO: ensure untrusted and free sizes - - // hash the epm contents - int valid = validate_and_hash_epm(&ctx, 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; + } + } - if(valid == -1){ - return SBI_ERR_SM_ENCLAVE_ILLEGAL_PTE; + 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, MSR_START_FILENAME) == 0) { + enclave->params.start_pc = ebase + id_res_resource->offset; + break; + } + } + if (!enclave->params.start_pc) { + return SBI_ERR_SM_ENCLAVE_ILLEGAL_ARGUMENT; } + 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 35e423889..b2308f795 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.dram_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); @@ -275,7 +271,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 +294,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,12 +338,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.free_base = base + create_args.free_offset; params.untrusted_base = utbase; params.untrusted_size = utsize; - params.free_requested = create_args.free_requested; // allocate eid @@ -670,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; diff --git a/sm/src/enclave.h b/sm/src/enclave.h index 0399a4d3d..ac38f606f 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]; @@ -116,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);