// Returns the pointer to the Enclave instance on success. uintptr_t _ECREATE(page_info_t* pi) { secs_t* secs = reinterpret_cast<secs_t*>(pi->src_page); // Enclave size must be at least 2 pages and a power of 2. GP_ON(!is_power_of_two((size_t)secs->size)); GP_ON(secs->size < (SE_PAGE_SIZE << 1)); CEnclaveSim* ce = new CEnclaveSim(secs); void* addr; // `ce' is not checked against NULL, since it is not // allocated with new(std::no_throw). addr = se_virtual_alloc(NULL, (size_t)secs->size, MEM_COMMIT); if (addr == NULL) { delete ce; return 0; } // Mark all the memory inaccessible. se_virtual_protect(addr, (size_t)secs->size, SGX_PROT_NONE); ce->get_secs()->base = addr; CEnclaveMngr::get_instance()->add(ce); return reinterpret_cast<uintptr_t>(ce); }
int add_enclave_page(sgx_enclave_id_t enclave_id, void *source, size_t offset, const sec_info_t &secinfo, uint32_t attr) { sec_info_t sinfo; page_info_t pinfo; CEnclaveMngr *mngr; CEnclaveSim *ce; UNUSED(attr); mngr = CEnclaveMngr::get_instance(); ce = mngr->get_enclave(enclave_id); if (ce == NULL) { SE_TRACE(SE_TRACE_DEBUG, "enclave (id = %llu) not found.\n", enclave_id); return SGX_ERROR_INVALID_ENCLAVE_ID; } memset(&sinfo, 0, sizeof(sec_info_t)); sinfo.flags = secinfo.flags; if(memcmp(&sinfo, &secinfo, sizeof(sec_info_t))) return SGX_ERROR_UNEXPECTED; memset(&pinfo, 0, sizeof(pinfo)); pinfo.secs = ce->get_secs(); pinfo.lin_addr = (char*)ce->get_secs()->base + offset; pinfo.src_page = source; pinfo.sec_info = &sinfo; /* Passing NULL here when there is no EPC mgmt. */ return (int)DoEADD_SW(&pinfo, GET_PTR(void, ce->get_secs()->base, offset)); }
/* Allocate linear address space. */ int create_enclave(secs_t *secs, sgx_enclave_id_t *enclave_id, void **start_addr) { CEnclaveSim *ce; sec_info_t sinfo; page_info_t pinfo; BUG_ON(secs == NULL, SGX_ERROR_UNEXPECTED); BUG_ON(enclave_id == NULL, SGX_ERROR_UNEXPECTED); BUG_ON(start_addr == NULL, SGX_ERROR_UNEXPECTED); memset(&sinfo, 0, sizeof(sinfo)); sinfo.flags = SI_FLAGS_SECS; memset(&pinfo, 0, sizeof(pinfo)); pinfo.src_page = secs; pinfo.sec_info = &sinfo; ce = reinterpret_cast<CEnclaveSim*>(DoECREATE_SW(&pinfo)); if (ce == NULL) { SE_TRACE(SE_TRACE_DEBUG, "out of memory.\n"); return SGX_ERROR_OUT_OF_MEMORY; } *start_addr = ce->get_secs()->base; *enclave_id = ce->get_enclave_id(); secs->base = *start_addr; return SGX_SUCCESS; }
uintptr_t _EREMOVE(const void *epc_lin_addr) { CEnclaveMngr *mngr = CEnclaveMngr::get_instance(); CEnclaveSim *ce = mngr->get_enclave(epc_lin_addr); GP_ON(!ce); GP_ON(!IS_PAGE_ALIGNED(epc_lin_addr)); return ce->remove_page(epc_lin_addr) ? 0 : -1; }
uintptr_t _EINIT(secs_t* secs, enclave_css_t *css, token_t *launch) { CEnclaveMngr *mngr = CEnclaveMngr::get_instance(); assert(mngr != NULL); CEnclaveSim* ce = mngr->get_enclave(secs); GP_ON(ce == NULL); GP_ON((ce->get_secs()->attributes.flags & SGX_FLAGS_INITTED) != 0); // Fill MREnclave, MRSigner, ISVPRODID, ISVSVN secs_t* this_secs = ce->get_secs(); if (css != NULL) { // Check signature if ((css->body.attribute_mask.xfrm & this_secs->attributes.xfrm) != (css->body.attribute_mask.xfrm & css->body.attributes.xfrm)) { SE_TRACE(SE_TRACE_DEBUG, "SECS attributes.xfrm does NOT match signature attributes.xfrm\n"); return SGX_ERROR_INVALID_ATTRIBUTE; } if ((css->body.attribute_mask.flags & this_secs->attributes.flags) != (css->body.attribute_mask.flags & css->body.attributes.flags)) { SE_TRACE(SE_TRACE_DEBUG, "SECS attributes.flag does NOT match signature attributes.flag\n"); return SGX_ERROR_INVALID_ATTRIBUTE; } mcp_same_size(&this_secs->mr_enclave, &css->body.enclave_hash, sizeof(sgx_measurement_t)); this_secs->isv_prod_id = css->body.isv_prod_id; this_secs->isv_svn = css->body.isv_svn; ippsHashMessage(css->key.modulus, SE_KEY_SIZE, (Ipp8u*)&this_secs->mr_signer, IPP_ALG_HASH_SHA256); } // Check launch token if (launch != NULL && launch->body.valid) { if (memcmp(&launch->body.attributes, &this_secs->attributes, sizeof(sgx_attributes_t))) { SE_TRACE(SE_TRACE_DEBUG, "SECS attributes does NOT match launch token attribuets\n"); return SGX_ERROR_INVALID_ATTRIBUTE; } } // Mark it initialized this_secs->attributes.flags |= SGX_FLAGS_INITTED; return SGX_SUCCESS; }
int init_enclave(sgx_enclave_id_t enclave_id, enclave_css_t *enclave_css, token_t *launch) { CEnclaveMngr* mngr = CEnclaveMngr::get_instance(); CEnclaveSim* ce = mngr->get_enclave(enclave_id); if (ce == NULL) { SE_TRACE(SE_TRACE_DEBUG, "enclave (id = %llu) not found.\n", enclave_id); return SGX_ERROR_INVALID_ENCLAVE_ID; } return (int)DoEINIT_SW(ce->get_secs(), enclave_css, launch); }
int destroy_enclave(sgx_enclave_id_t enclave_id) { CEnclaveMngr* mngr = CEnclaveMngr::get_instance(); CEnclaveSim* ce = mngr->get_enclave(enclave_id); if (ce == NULL) { SE_TRACE(SE_TRACE_DEBUG, "enclave (id = %llu) not found.\n", enclave_id); return SGX_ERROR_INVALID_ENCLAVE_ID; } /* In simulation mode, all allocated pages will be freed upon the later `delete ce'. Just remove the first page here. */ DoEREMOVE_SW(0, ce->get_secs()->base); mngr->remove(ce); delete ce; return SGX_SUCCESS; }
uintptr_t _EADD(page_info_t* pi, void *epc_lin_addr) { void *src_page = pi->src_page; CEnclaveMngr *mngr = CEnclaveMngr::get_instance(); CEnclaveSim *ce = mngr->get_enclave(pi->lin_addr); if (ce == NULL) { SE_TRACE(SE_TRACE_DEBUG, "failed to get enclave instance\n"); return SGX_ERROR_UNEXPECTED; } GP_ON(!IS_PAGE_ALIGNED(epc_lin_addr)); GP_ON((ce->get_secs()->attributes.flags & SGX_FLAGS_INITTED) != 0); // Make the page writable before doing memcpy() se_virtual_protect(epc_lin_addr, SE_PAGE_SIZE, SI_FLAGS_RW); mcp_same_size(epc_lin_addr, src_page, SE_PAGE_SIZE); se_virtual_protect(epc_lin_addr, SE_PAGE_SIZE, (uint32_t)pi->sec_info->flags); GP_ON(!ce->add_page(pi->lin_addr, pi->sec_info->flags)); return SGX_SUCCESS; }
void _SE3(uintptr_t xax, uintptr_t xbx, uintptr_t xcx, uintptr_t xdx, uintptr_t xsi, uintptr_t xdi) { UNUSED(xdx); switch (xax) { case SE_EENTER: uintptr_t xip; void * enclave_base_addr; se_pt_regs_t* p_pt_regs; tcs_t* tcs; tcs_sim_t* tcs_sim; ssa_gpr_t* p_ssa_gpr; secs_t* secs; CEnclaveMngr* mngr; CEnclaveSim* ce; // xbx contains the address of a TCS tcs = reinterpret_cast<tcs_t*>(xbx); // Is TCS pointer page-aligned? GP_ON_EENTER(!IS_PAGE_ALIGNED(tcs)); mngr = CEnclaveMngr::get_instance(); assert(mngr != NULL); // Is it really a TCS? ce = mngr->get_enclave(tcs); GP_ON_EENTER(ce == NULL); GP_ON_EENTER(!ce->is_tcs_page(tcs)); // Check the EntryReason tcs_sim = reinterpret_cast<tcs_sim_t *>(tcs->reserved); GP_ON_EENTER(tcs_sim->tcs_state != TCS_STATE_INACTIVE); GP_ON_EENTER(tcs->cssa >= tcs->nssa); secs = ce->get_secs(); enclave_base_addr = secs->base; p_ssa_gpr = reinterpret_cast<ssa_gpr_t*>(reinterpret_cast<uintptr_t>(enclave_base_addr) + static_cast<size_t>(tcs->ossa) + secs->ssa_frame_size * SE_PAGE_SIZE - sizeof(ssa_gpr_t)); tcs_sim->saved_aep = xcx; p_pt_regs = reinterpret_cast<se_pt_regs_t*>(get_bp()); p_ssa_gpr->REG(bp_u) = p_pt_regs->xbp; p_ssa_gpr->REG(sp_u) = reinterpret_cast<uintptr_t>(p_pt_regs + 1); xcx = p_pt_regs->xip; xip = reinterpret_cast<uintptr_t>(enclave_base_addr); GP_ON_EENTER(xip == 0); //set the _tls_array to point to the self_addr of TLS section inside the enclave GP_ON_EENTER(td_mngr_set_td(enclave_base_addr, tcs) == false); // Destination depends on STATE xip += (uintptr_t)tcs->oentry; tcs_sim->tcs_state = TCS_STATE_ACTIVE; // Link the TCS to the thread GP_ON_EENTER((secs->attributes.flags & SGX_FLAGS_INITTED) == 0); // Replace the return address on the stack with the enclave entry, // so that when we return from this function, we'll enter the enclave. enclu_regs_t regs; regs.xax = tcs->cssa; regs.xbx = reinterpret_cast<uintptr_t>(tcs); regs.xcx = xcx; regs.xdx = 0; regs.xsi = xsi; regs.xdi = xdi; regs.xbp = p_ssa_gpr->REG(bp_u); regs.xsp = p_ssa_gpr->REG(sp_u); regs.xip = xip; load_regs(®s); // Returning from this function enters the enclave return; default: // There's only 1 ring 3 instruction outside the enclave: EENTER. GP(); } }