diff options
Diffstat (limited to 'src/sgx.rs')
-rw-r--r-- | src/sgx.rs | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/src/sgx.rs b/src/sgx.rs new file mode 100644 index 0000000..e611620 --- /dev/null +++ b/src/sgx.rs @@ -0,0 +1,351 @@ +//! Program x86 enclaves. + +/// Execute an enclave system function of specified leaf number. +/// +/// # Safety +/// * Function needs to be executed in ring 0. +macro_rules! encls { + ($rax:expr, $rbx:expr) + => ( $crate::sgx::encls2($rax as u64, $rbx as u64) ); + + ($rax:expr, $rbx:expr, $rcx:expr) + => ( $crate::sgx::encls3($rax as u64, $rbx as u64, $rcx as u64) ); + + ($rax:expr, $rbx:expr, $rcx:expr, $rdx:expr) + => ( $crate::sgx::encls4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64) ); +} + +/// encls with two arguments -- consider calling the encls! macro instead! +unsafe fn encls2(rax: u64, rbx: u64) -> (u32, u64) { + let eax: u32; + let out_rbx: u64; + asm!("encls" : "={eax}" (eax), "={rbx}" (out_rbx) + : "{rax}" (rax), "{rbx}" (rbx)); + (eax, out_rbx) +} + +/// encls with three arguments -- consider calling the encls! macro instead! +unsafe fn encls3(rax: u64, rbx: u64, rcx: u64) -> (u32, u64) { + let eax: u32; + let out_rbx: u64; + asm!("encls" : "={eax}" (eax), "={rbx}" (out_rbx) + : "{rax}" (rax), "{rbx}" (rbx), "{rcx}" (rcx)); + (eax, out_rbx) +} + +/// encls with four arguments -- consider calling the encls! macro instead! +unsafe fn encls4(rax: u64, rbx: u64, rcx: u64, rdx: u64) -> (u32, u64) { + let eax: u32; + let out_rbx: u64; + asm!("encls" : "={eax}" (eax), "={rbx}" (out_rbx) + : "{rax}" (rax), "{rbx}" (rbx), "{rcx}" (rcx), "{rdx}" (rdx)); + (eax, out_rbx) +} + +enum EnclsCommand { + EADD = 0x01, + EAUG = 0x0D, + EBLOCK = 0x09, + ECREATE = 0x00, + EDBGRD = 0x04, + EDBGWR = 0x05, + EEXTEND = 0x06, + EINIT = 0x02, + ELDB = 0x07, + ELDU = 0x08, + EMODPR = 0x0E, + EMODT = 0x0F, + EPA = 0x0A, + EREMOVE = 0x03, + ETRACK = 0x0C, + EWB = 0x0B +} + + +/// Add a Page to an Uninitialized Enclave. +/// +/// # Arguments +/// * Address of a PAGEINFO. +/// * Address of the destination EPC page. +pub unsafe fn encls_eadd(pageinfo: u64, epc_page: u64) { + encls!(EnclsCommand::EADD as u64, pageinfo, epc_page); +} + +/// Add a Page to an Initialized Enclave. +/// +/// # Arguments +/// * Address of a SECINFO +/// * Address of the destination EPC page +pub unsafe fn encls_eaug(secinfo_address: u64, epc_page: u64) { + encls!(EnclsCommand::EAUG as u64, secinfo_address, epc_page); +} + +/// Mark a page in EPC as Blocked. +/// +/// # Arguments +/// * Effective address of the EPC page +pub unsafe fn encls_eblock(epc_page: u64) -> u32 { + encls!(EnclsCommand::EBLOCK as u64, epc_page).0 +} + +/// Create an SECS page in the Enclave Page Cache +/// +/// # Arguments +/// * Address of a PAGEINFO +/// * Address of the destination SECS page +/// +pub unsafe fn encls_create(pageinfo: u64, secs_page: u64) { + encls!(EnclsCommand::ECREATE as u64, pageinfo, secs_page); +} + +/// Read From a Debug Enclave. +/// +/// # Return +/// Data read from a debug enclave. +/// +/// # Arguments +/// * Address of source memory in the EPC +/// +pub unsafe fn encls_edbgrd(source_address: u64) -> u64 { + encls!(EnclsCommand::EDBGRD as u64, source_address).1 +} + +/// Write to a Debug Enclave. +/// +/// # Arguments +/// * Data to be written to a debug enclave +/// * Address of Target memory in the EPC +/// +pub unsafe fn encls_edbgwr(data: u64, target_address: u64) { + encls!(EnclsCommand::EDBGWR as u64, data, target_address); +} + +/// Extend Uninitialized Enclave Measurement by 256 Bytes +/// +/// # Arguments +/// * Effective address of the SECS of the data chunk +/// * Effective address of a 256-byte chunk in the EPC +pub unsafe fn encls_eextend(secs_chunk: u64, epc_chunk: u64) { + encls!(EnclsCommand::EEXTEND as u64, secs_chunk, epc_chunk); +} + +/// Initialize an Enclave for Execution +/// +/// # Arguments +/// * Address of SIGSTRUCT +/// * Address of SECS +/// * Address of EINITTOKEN +/// +pub unsafe fn encls_einit(sigstruct: u64, secs: u64, einittoken: u64) -> u32 { + encls!(EnclsCommand::EINIT as u64, sigstruct, secs, einittoken).0 +} + +/// Loads and verifies an EPC page and marks the page as blocked. +/// +/// # Arguments +/// * Address of the PAGEINFO +/// * Address of the EPC page +/// * Address of the version-array slot +/// +pub unsafe fn encls_eldb(pageinfo: u64, epc_page: u64, verion_array_slot: u64) -> u32 { + encls!(EnclsCommand::ELDB as u64, pageinfo, epc_page, verion_array_slot).0 +} + +/// Loads, verifies an EPC page and marks the page as unblocked. +/// +/// # Arguments +/// * Address of the PAGEINFO +/// * Address of the EPC page +/// * Address of the version-array slot +/// +pub unsafe fn encls_eldu(pageinfo: u64, epc_page: u64, verion_array_slot: u64) -> u32 { + encls!(EnclsCommand::ELDU as u64, pageinfo, epc_page, verion_array_slot).0 +} + +/// Restrict the Permissions of an EPC Page. +/// +/// # Arguments +/// * Address of a SECINFO +/// * Address of the destination EPC page +/// +pub unsafe fn encls_emodpr(secinfo: u64, epc_page: u64) -> u32 { + encls!(EnclsCommand::EMODPR as u64, secinfo, epc_page).0 +} + +/// Change the Type of an EPC Page. +/// +/// # Arguments +/// * Address of a SECINFO +/// * Address of the destination EPC page +/// +pub unsafe fn encls_emodt(secinfo: u64, epc_page: u64) -> u32 { + encls!(EnclsCommand::EMODT as u64, secinfo, epc_page).0 +} + +/// Add Version Array. +/// +/// # Arguments +/// * PT_VA Constant +/// * Effective address of the EPC page +/// +pub unsafe fn encls_epa(pt_va: u64, epc_page: u64) { + encls!(EnclsCommand::EPA as u64, pt_va, epc_page); +} + +/// Remove a page from the EPC. +/// +/// # Arguments +/// * Effective address of the EPC page +/// +pub unsafe fn encls_eremove(epc_page: u64) { + encls!(EnclsCommand::EREMOVE as u64, epc_page); +} + +/// Activates EBLOCK Checks. +/// +/// # Arguments +/// * Pointer to the SECS of the EPC page. +/// +pub unsafe fn encls_etrack(secs_pointer: u64) -> u32 { + encls!(EnclsCommand::ETRACK as u64, secs_pointer).0 +} + +/// Invalidate an EPC Page and Write out to Main Memory. +/// +/// # Arguments +/// * Address of the EPC page. +/// * Address of a VA slot. +/// +pub unsafe fn encls_ewb(pageinfo: u64, epc_page: u64, va_slot: u64) -> u32 { + encls!(EnclsCommand::EWB as u64, pageinfo, epc_page, va_slot).0 +} + +/// Execute an enclave user function of specified leaf number. +/// +/// # Safety +/// * Function needs to be executed in ring 3. +macro_rules! enclu { + ($rax:expr, $rbx:expr, $rcx:expr) + => ( $crate::sgx::enclu3($rax as u64, $rbx as u64, $rcx as u64) ); + + ($rax:expr, $rbx:expr, $rcx:expr, $rdx:expr) + => ( $crate::sgx::enclu4($rax as u64, $rbx as u64, $rcx as u64, $rdx as u64) ); +} + +/// enclu with three arguments -- consider calling the enclu! macro instead! +unsafe fn enclu3(rax: u64, rbx: u64, rcx: u64) -> (u32, u64) { + let eax: u32; + let out_rcx: u64; + asm!("enclu" : "={eax}" (eax), "={rcx}" (out_rcx) + : "{rax}" (rax), "{rbx}" (rbx), "{rcx}" (rcx)); + (eax, out_rcx) +} + +/// enclu with four arguments -- consider calling the enclu! macro instead! +unsafe fn enclu4(rax: u64, rbx: u64, rcx: u64, rdx: u64) -> (u32, u64) { + let eax: u32; + let out_rcx: u64; + asm!("enclu" : "={eax}" (eax), "={rcx}" (out_rcx) + : "{rax}" (rax), "{rbx}" (rbx), "{rcx}" (rcx), "{rdx}" (rdx)); + (eax, out_rcx) +} + +enum EncluCommand { + EACCEPT = 0x05, + EACCEPTCOPY = 0x07, + EENTER = 0x02, + EEXIT = 0x04, + EGETKEY = 0x01, + EMODEPE = 0x06, + EREPORT = 0x00, + ERESUME = 0x03, +} + +/// Accept Changes to an EPC Page. +/// +/// # Arguments +/// * Address of a SECINFO. +/// * Address of the destination EPC page. +/// +/// Returns an error code. +/// +pub unsafe fn enclu_eaccept(secinfo: u64, epc_page: u64) -> u32 { + enclu!(EncluCommand::EACCEPT as u64, secinfo, epc_page).0 +} + +/// Initialize a Pending Page. +/// +/// # Arguments +/// * Address of a SECINFO. +/// * Address of the destination EPC page. +/// * Address of the source EPC page. +/// +/// Returns an error code. +/// +pub unsafe fn enclu_eacceptcopy(secinfo: u64, destination_epc_page: u64, source_epc_page: u64) -> u32 { + enclu!(EncluCommand::EACCEPTCOPY as u64, secinfo, destination_epc_page, source_epc_page).0 +} + +/// Enters an Enclave. +/// +/// # Arguments +/// * Address of a TCS. +/// * Address of AEP. +/// * Address of IP following EENTER. +/// +/// Returns content of RBX.CSSA and Address of IP following EENTER. +/// +pub unsafe fn enclu_eenter(tcs: u64, aep: u64) -> (u32, u64) { + enclu!(EncluCommand::EENTER as u64, tcs, aep) +} + +/// Exits an Enclave. +/// +/// # Arguments +/// * Target address outside the enclave +/// * Address of the current AEP +/// +pub unsafe fn enclu_eexit(ip: u64, aep: u64) { + enclu!(EncluCommand::EEXIT as u64, ip, aep); +} + +/// Retrieves a Cryptographic Key. +/// +/// # Arguments +/// * Address to a KEYREQUEST +/// * Address of the OUTPUTDATA +/// +pub unsafe fn enclu_egetkey(keyrequest: u64, outputdata: u64) { + enclu!(EncluCommand::EGETKEY as u64, keyrequest, outputdata); +} + +/// Extend an EPC Page Permissions. +/// +/// # Arguments +/// * Address of a SECINFO +/// * Address of the destination EPC page +/// +pub unsafe fn enclu_emodepe(secinfo: u64, epc_page: u64) { + enclu!(EncluCommand::EMODEPE as u64, secinfo, epc_page); +} + +/// Create a Cryptographic Report of the Enclave. +/// +/// # Arguments +/// * Address of TARGETINFO +/// * Address of REPORTDATA +/// * Address where the REPORT is written to in an OUTPUTDATA +/// +pub unsafe fn enclu_ereport(targetinfo: u64, reportdata: u64, outputdata: u64) { + enclu!(EncluCommand::EREPORT as u64, targetinfo, reportdata, outputdata); +} + +/// Re-Enters an Enclave. +/// +/// # Arguments +/// * Address of a TCS. +/// * Address of AEP. +/// +pub unsafe fn enclu_eresume(tcs: u64, aep: u64) { + enclu!(EncluCommand::ERESUME as u64, tcs, aep); +} |