From b83429ece9ea71aa12ba47ba99af0dc214d380b0 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 9 Jun 2023 19:10:43 +0800 Subject: [PATCH 01/20] Implement enclave memory management --- sgx_trts/Cargo.toml | 4 + sgx_trts/src/arch.rs | 16 +- sgx_trts/src/call/ocall.rs | 8 +- sgx_trts/src/edmm/epc.rs | 15 +- sgx_trts/src/edmm/mem.rs | 12 +- sgx_trts/src/edmm/mod.rs | 2 +- sgx_trts/src/edmm/perm.rs | 70 ++++++ sgx_trts/src/edmm/tcs.rs | 6 +- sgx_trts/src/emm/alloc.rs | 31 +++ sgx_trts/src/emm/bitmap.rs | 160 ++++++++++++ sgx_trts/src/emm/ema.rs | 454 +++++++++++++++++++++++++++++++++++ sgx_trts/src/emm/emalist.rs | 31 +++ sgx_trts/src/emm/flags.rs | 82 +++++++ sgx_trts/src/emm/interior.rs | 242 +++++++++++++++++++ sgx_trts/src/emm/mod.rs | 24 ++ sgx_trts/src/emm/user.rs | 96 ++++++++ sgx_trts/src/lib.rs | 4 + 17 files changed, 1241 insertions(+), 16 deletions(-) create mode 100644 sgx_trts/src/emm/alloc.rs create mode 100644 sgx_trts/src/emm/bitmap.rs create mode 100644 sgx_trts/src/emm/ema.rs create mode 100644 sgx_trts/src/emm/emalist.rs create mode 100644 sgx_trts/src/emm/flags.rs create mode 100644 sgx_trts/src/emm/interior.rs create mode 100644 sgx_trts/src/emm/mod.rs create mode 100644 sgx_trts/src/emm/user.rs diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml index 82282e683..d1e2cb4e2 100644 --- a/sgx_trts/Cargo.toml +++ b/sgx_trts/Cargo.toml @@ -39,3 +39,7 @@ hyper = ["sgx_types/hyper"] sgx_types = { path = "../sgx_types" } sgx_crypto_sys = { path = "../sgx_crypto/sgx_crypto_sys" } sgx_tlibc_sys = { path = "../sgx_libc/sgx_tlibc_sys" } +intrusive-collections = "0.9.5" +buddy_system_allocator = "0.9.0" +spin = "0.9.4" +bitflags = "1.3" diff --git a/sgx_trts/src/arch.rs b/sgx_trts/src/arch.rs index d36fb09a9..0350fa256 100644 --- a/sgx_trts/src/arch.rs +++ b/sgx_trts/src/arch.rs @@ -40,12 +40,24 @@ macro_rules! is_page_aligned { }; } +macro_rules! round_to { + ($num:expr, $align:expr) => { + ($num + $align - 1) & (!($align - 1)) + }; +} + macro_rules! round_to_page { ($num:expr) => { ($num + crate::arch::SE_PAGE_SIZE - 1) & (!(crate::arch::SE_PAGE_SIZE - 1)) }; } +macro_rules! trim_to { + ($num:expr, $align:expr) => { + $num & (!($align - 1)) + }; +} + macro_rules! trim_to_page { ($num:expr) => { $num & (!(crate::arch::SE_PAGE_SIZE - 1)) @@ -726,8 +738,8 @@ impl From for SecInfoFlags { impl From for SecInfoFlags { fn from(data: edmm::PageInfo) -> SecInfoFlags { let typ = data.typ as u64; - let flags = data.flags.bits() as u64; - SecInfoFlags::from_bits_truncate((typ << 8) | flags) + let prot = data.prot.bits() as u64; + SecinfoFlags::from_bits_truncate((typ << 8) | prot) } } diff --git a/sgx_trts/src/call/ocall.rs b/sgx_trts/src/call/ocall.rs index ea60ea485..207329e60 100644 --- a/sgx_trts/src/call/ocall.rs +++ b/sgx_trts/src/call/ocall.rs @@ -34,11 +34,13 @@ pub enum OCallIndex { TrimCommit, Modpr, Mprotect, + Alloc, + Modify, } impl OCallIndex { pub fn is_builtin_index(index: i32) -> bool { - (-5..=-2).contains(&index) + (-7..=-2).contains(&index) } pub fn is_builtin(&self) -> bool { @@ -62,6 +64,8 @@ impl TryFrom for OCallIndex { -3 => Ok(OCallIndex::TrimCommit), -4 => Ok(OCallIndex::Modpr), -5 => Ok(OCallIndex::Mprotect), + -6 => Ok(OCallIndex::Alloc), + -7 => Ok(OCallIndex::Modify), _ => Err(u8::try_from(256_u16).unwrap_err()), } } @@ -76,6 +80,8 @@ impl From for i32 { OCallIndex::TrimCommit => -3, OCallIndex::Modpr => -4, OCallIndex::Mprotect => -5, + OCallIndex::Alloc => -6, + OCallIndex::Modify => -7, } } } diff --git a/sgx_trts/src/edmm/epc.rs b/sgx_trts/src/edmm/epc.rs index 05c966ad1..2465a4ce0 100644 --- a/sgx_trts/src/edmm/epc.rs +++ b/sgx_trts/src/edmm/epc.rs @@ -34,10 +34,13 @@ impl_enum! { } } +// ProtFlags may have richer meaning compared to ProtFlags +// ProtFlags and AllocFlags are confused to developer +// PageInfo->flags should change to PageInfo->prot impl_bitflags! { #[repr(C)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub struct PageFlags: u8 { + pub struct ProtFlags: u8 { const NONE = 0x00; const R = 0x01; const W = 0x02; @@ -51,7 +54,13 @@ impl_bitflags! { #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct PageInfo { pub typ: PageType, - pub flags: PageFlags, + pub prot: ProtFlags, +} + +impl Into for PageInfo { + fn into(self) -> u32 { + (Into::::into(self.typ) as u32) << 8 | (self.prot.bits() as u32) + } } unsafe impl ContiguousMemory for PageInfo {} @@ -106,7 +115,7 @@ impl PageRange { pub(crate) fn modify(&self) -> SgxResult { for page in self.iter() { let _ = page.modpe(); - if !page.info.flags.contains(PageFlags::W | PageFlags::X) { + if !page.info.prot.contains(ProtFlags::W | ProtFlags::X) { page.accept()?; } } diff --git a/sgx_trts/src/edmm/mem.rs b/sgx_trts/src/edmm/mem.rs index 0d6ac634d..18b1581d5 100644 --- a/sgx_trts/src/edmm/mem.rs +++ b/sgx_trts/src/edmm/mem.rs @@ -26,7 +26,7 @@ cfg_if! { #[cfg(not(any(feature = "sim", feature = "hyper")))] mod hw { use crate::arch::{self, Layout}; - use crate::edmm::epc::{PageFlags, PageInfo, PageRange, PageType}; + use crate::edmm::epc::{PageInfo, PageRange, PageType, ProtFlags}; use crate::edmm::layout::LayoutTable; use crate::edmm::perm; use crate::edmm::trim; @@ -47,7 +47,7 @@ mod hw { count, PageInfo { typ: PageType::Reg, - flags: PageFlags::R | PageFlags::W | PageFlags::PENDING, + prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, }, )?; if (attr.attr & arch::PAGE_DIR_GROW_DOWN) == 0 { @@ -74,7 +74,7 @@ mod hw { count, PageInfo { typ: PageType::Trim, - flags: PageFlags::MODIFIED, + prot: ProtFlags::MODIFIED, }, )?; pages.accept_forward()?; @@ -96,7 +96,7 @@ mod hw { count, PageInfo { typ: PageType::Reg, - flags: PageFlags::R | PageFlags::W | PageFlags::PENDING, + prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, }, )?; pages.accept_forward()?; @@ -131,7 +131,7 @@ mod hw { count, PageInfo { typ: PageType::Trim, - flags: PageFlags::MODIFIED, + prot: ProtFlags::MODIFIED, }, )?; pages.accept_forward()?; @@ -196,7 +196,7 @@ mod hw { count, PageInfo { typ: PageType::Reg, - flags: PageFlags::PR | PageFlags::from_bits_truncate(perm), + prot: ProtFlags::PR | ProtFlags::from_bits_truncate(perm), }, )?; diff --git a/sgx_trts/src/edmm/mod.rs b/sgx_trts/src/edmm/mod.rs index 420dbccb4..c54b036b0 100644 --- a/sgx_trts/src/edmm/mod.rs +++ b/sgx_trts/src/edmm/mod.rs @@ -24,6 +24,6 @@ pub(crate) mod tcs; #[cfg(not(any(feature = "sim", feature = "hyper")))] pub(crate) mod trim; -pub use epc::{PageFlags, PageInfo, PageRange, PageType}; +pub use epc::{PageInfo, PageRange, PageType, ProtFlags}; pub use mem::{apply_epc_pages, trim_epc_pages}; pub use perm::{modpr_ocall, mprotect_ocall}; diff --git a/sgx_trts/src/edmm/perm.rs b/sgx_trts/src/edmm/perm.rs index 4e17e67e5..31368064b 100644 --- a/sgx_trts/src/edmm/perm.rs +++ b/sgx_trts/src/edmm/perm.rs @@ -27,6 +27,8 @@ cfg_if! { mod hw { use crate::arch::SE_PAGE_SHIFT; use crate::call::{ocall, OCallIndex, OcAlloc}; + use crate::edmm::{PageInfo, PageType}; + use crate::emm::flags::AllocFlags; use alloc::boxed::Box; use core::convert::Into; use sgx_types::error::{SgxResult, SgxStatus}; @@ -67,6 +69,74 @@ mod hw { ocall(OCallIndex::Mprotect, Some(change.as_mut())) } + + // In keeping with Intel SDK, here we use the name page_properties, + // but page_type: PageType is more appropriate + #[repr(C)] + #[derive(Clone, Copy, Debug, Default)] + struct EmmAllocOcall { + retval: i32, + addr: usize, + size: usize, + page_properties: u32, + alloc_flags: u32, + } + + /// FIXME: fake alloc + pub fn alloc_ocall( + addr: usize, + length: usize, + page_type: PageType, + alloc_flags: AllocFlags, + ) -> SgxResult { + let mut change = Box::try_new_in( + EmmAllocOcall { + retval: 0, // not sure + addr, + size: length, + page_properties: Into::::into(page_type) as u32, + alloc_flags: alloc_flags.bits(), + }, + OcAlloc, + ) + .map_err(|_| SgxStatus::OutOfMemory)?; + + ocall(OCallIndex::Alloc, Some(change.as_mut())) + } + + // In keeping with Intel SDK, here we use the name flags_from (si_flags), + // but we rename si_flags to page_info, here info_from: PageInfo is more appropriate + #[repr(C)] + #[derive(Clone, Copy, Debug, Default)] + struct EmmModifyOcall { + retval: i32, + addr: usize, + size: usize, + flags_from: u32, + flags_to: u32, + } + + /// FIXME: fake modify + pub fn modify_ocall( + addr: usize, + length: usize, + info_from: PageInfo, + info_to: PageInfo, + ) -> SgxResult { + let mut change = Box::try_new_in( + EmmModifyOcall { + retval: 0, + addr, + size: length, + flags_from: Into::::into(info_from), + flags_to: Into::::into(info_to), + }, + OcAlloc, + ) + .map_err(|_| SgxStatus::OutOfMemory)?; + + ocall(OCallIndex::Modify, Some(change.as_mut())) + } } #[cfg(any(feature = "sim", feature = "hyper"))] diff --git a/sgx_trts/src/edmm/tcs.rs b/sgx_trts/src/edmm/tcs.rs index 271b94e24..e92d77be3 100644 --- a/sgx_trts/src/edmm/tcs.rs +++ b/sgx_trts/src/edmm/tcs.rs @@ -63,7 +63,7 @@ pub fn mktcs(mk_tcs: NonNull) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] mod hw { use crate::arch::{self, Layout, Tcs}; - use crate::edmm::epc::{Page, PageFlags, PageInfo, PageType}; + use crate::edmm::epc::{Page, PageInfo, PageType, ProtFlags}; use crate::enclave::MmLayout; use crate::tcs::list; use core::ptr; @@ -123,7 +123,7 @@ mod hw { tcs.as_ptr() as usize, PageInfo { typ: PageType::Tcs, - flags: PageFlags::MODIFIED, + prot: ProtFlags::MODIFIED, }, )?; page.accept()?; @@ -175,7 +175,7 @@ mod hw { tcs.as_ptr() as usize, PageInfo { typ: PageType::Trim, - flags: PageFlags::MODIFIED, + prot: ProtFlags::MODIFIED, }, )?; page.accept()?; diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs new file mode 100644 index 000000000..30e1d7008 --- /dev/null +++ b/sgx_trts/src/emm/alloc.rs @@ -0,0 +1,31 @@ +use core::alloc::{AllocError, Allocator, Layout}; +use core::ptr::NonNull; + +/// alloc layout memory from Reserve region +#[derive(Clone)] +pub struct ResAlloc; + +unsafe impl Allocator for ResAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + todo!() + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + todo!() + } +} + +#[derive(Clone)] +pub struct StaticAlloc; + +unsafe impl Allocator for StaticAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + todo!() + } + + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + todo!() + } +} diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs new file mode 100644 index 000000000..5a7e1e370 --- /dev/null +++ b/sgx_trts/src/emm/bitmap.rs @@ -0,0 +1,160 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. +use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; +use core::alloc::Allocator; +use core::clone::Clone; +use sgx_types::error::SgxResult; +use sgx_types::error::SgxStatus; + +// box 能否 #[repr(C)] +#[derive(Clone)] +pub struct BitArray { + pub bits: usize, + pub bytes: usize, + pub data: Box<[u8], A>, // temporariy use ResAlloc + alloc: A, +} + +impl BitArray { + /// Init BitArray in Reserve memory with all zeros. + pub fn new_in(bits: usize, alloc: A) -> SgxResult { + let bytes = (bits + 7) / 8; + + // FIXME: return error if out of memory + let data: Box<[u8], A> = vec::from_elem_in(0_u8, bytes, alloc.clone()).into_boxed_slice(); + Ok(Self { + bits, + bytes, + data, + alloc, + }) + } + + // Get the value of the bit at a given index. + // todo: return SgxResult + pub fn get(&self, index: usize) -> bool { + let byte_index = index / 8; + let bit_index = index % 8; + let bit_mask = 1 << bit_index; + (self.data.get(byte_index).unwrap() & bit_mask) != 0 + } + + // Set the value of the bit at a given index. + pub fn set(&mut self, index: usize, value: bool) { + let byte_index = index / 8; + let bit_index = index % 8; + let bit_mask = 1 << bit_index; + + let data = self.data.as_mut(); + if value { + data[byte_index] |= bit_mask; + } else { + data[byte_index] &= !bit_mask; + } + } + + // return chunk range with all true, Vec<[start, end)> + pub fn true_range(&self) -> Vec<(usize, usize), A> { + let mut true_range: Vec<(usize, usize), A> = Vec::new_in(self.alloc.clone()); + + let start: usize = 0; + let end: usize = self.bits; + + // TODO: optimized with [u8] slice + while start < end { + let mut block_start = start; + while block_start < end { + if self.get(block_start) { + break; + } else { + block_start += 1; + } + } + + if block_start == end { + break; + } + + let mut block_end = block_start + 1; + while block_end < end { + if self.get(block_end) { + block_end += 1; + } else { + break; + } + } + true_range.push((start,end)); + } + + return true_range; + } + + /// Set the value of the bit at a given index. + /// The range includes [0, index). + pub fn set_until(&mut self, index: usize, value: bool) { + todo!() + } + + /// Set the value of the bit at a given index. + /// The range includes [0, index). + pub fn set_full(&mut self) { + self.data.fill(0xFF); + } + + /// Clear all the bits + pub fn clear(&mut self) { + self.data.fill(0); + } + + // split current bit array into left and right bit array + // return right bit array + pub fn split(&mut self, pos: usize) -> SgxResult> { + ensure!(pos > 0 && pos < self.bits, SgxStatus::InvalidParameter); + + let byte_index = pos / 8; + let bit_index = pos % 8; + + // let l_bits = (byte_index << 3) + bit_index; + let l_bits = pos; + let l_bytes = (l_bits + 7) / 8; + + let r_bits = self.bits - l_bits; + let r_bytes = (r_bits + 7) / 8; + + let mut r_array = Self::new_in(r_bits, self.alloc.clone())?; + + for (idx, item) in r_array.data[..(r_bytes - 1)].iter_mut().enumerate() { + // current byte index in previous bit_array + let curr_idx = idx + byte_index; + let low_bits = self.data[curr_idx] >> bit_index; + let high_bits = self.data[curr_idx + 1] << (8 - bit_index); + *item = high_bits | low_bits; + } + r_array.data[r_bytes - 1] = self.data[self.bytes - 1] >> bit_index; + + self.bits = l_bits; + self.bytes = l_bytes; + + return Ok(r_array); + } +} + + + +// FIXME: add more unit test \ No newline at end of file diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs new file mode 100644 index 000000000..cee7e1516 --- /dev/null +++ b/sgx_trts/src/emm/ema.rs @@ -0,0 +1,454 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +use core::alloc::Allocator; + +use crate::arch::Secinfo; +use crate::arch::SecinfoFlags; +use crate::edmm::perm; +use crate::edmm::PageRange; +use crate::edmm::{PageInfo, PageType, ProtFlags}; +use crate::enclave::is_within_enclave; +use alloc::boxed::Box; +use intrusive_collections::intrusive_adapter; +use intrusive_collections::LinkedListLink; +use sgx_types::error::SgxResult; +use sgx_types::error::SgxStatus; + +use crate::feature::SysFeatures; +use crate::trts::Version; +use crate::veh::{ExceptionHandler, ExceptionInfo}; + +use super::alloc::ResAlloc; +use super::bitmap::BitArray; +use super::flags::AllocFlags; + +// pub struct Box(_, _) +// where +// A: Allocator, +// T: ?Sized; + +#[repr(C)] +#[derive(Clone)] +pub struct EMA +where + A: Allocator + Clone, +{ + // starting address, page aligned + start: usize, + // bytes, or page may be more available + length: usize, + alloc_flags: AllocFlags, + info: PageInfo, + // bitmap for EACCEPT status + eaccept_map: Option>, + // custom PF handler (for EACCEPTCOPY use) + handler: Option, + // private data for handler + priv_data: Option<*mut ExceptionInfo>, + alloc: A, + // intrusive linkedlist + link: LinkedListLink, +} + +impl EMA +where + A: Allocator + Clone, +{ + // start address must be page aligned + pub fn new( + start: usize, + length: usize, + alloc_flags: AllocFlags, + info: PageInfo, + handler: Option, + priv_data: Option<*mut ExceptionInfo>, + alloc: A, + ) -> SgxResult { + // check flags' eligibility + AllocFlags::try_from(alloc_flags.bits())?; + if start != 0 + && length != 0 + && is_within_enclave(start as *const u8, length) + && is_page_aligned!(start) + && (length % crate::arch::SE_PAGE_SIZE) == 0 + { + return Ok(Self { + start, + length, + alloc_flags, + info, + eaccept_map: None, + handler, + priv_data, + link: LinkedListLink::new(), + alloc, + }); + } else { + return Err(SgxStatus::InvalidParameter); + } + } + + // Returns a newly allocated ema in charging of the memory in the range [addr, len). + // After the call, the original ema will be left containing the elements [0, addr) + // with its previous capacity unchanged. + pub fn split(&mut self, addr: usize) -> SgxResult,A>> { + let l_start = self.start; + let l_length = addr - l_start; + + let r_start = addr; + let r_length = (self.start + self.length) - addr; + + let new_bitarray = match &mut self.eaccept_map{ + Some(bitarray) => { + let pos = (addr - self.start) >> crate::arch::SE_PAGE_SHIFT; + // split self.eaccept_map + Some(bitarray.split(pos)?) + } + None => { + None + } + }; + + // 这里之后可以优化 + // 1. self.clone() 会把原有的bitmap重新alloc并复制一份,但其实clone之后这里是None即可 + // 2. 使用Box::new_in 会把 self.clone() 这部分在栈上的数据再拷贝一份到Box新申请的内存区域 + let mut new_ema: Box,A> = Box::new_in( + self.clone(), + self.alloc.clone() + ); + + self.start = l_start; + self.length = l_length; + + new_ema.start = r_start; + new_ema.length = r_length; + new_ema.eaccept_map = new_bitarray; + + return Ok(new_ema); + } + + // If the previous ema is divided into three parts -> (left ema, middle ema, right ema), return (middle ema, right ema). + // If the previous ema is divided into two parts -> (left ema, right ema) + // end split: return (None, right ema), start split: return (left ema, None) + fn split_into_three(&mut self, start: usize, length: usize) -> SgxResult<(Option,A>>, Option,A>>)> { + if start > self.start { + let mut new_ema = self.split(start)?; + if new_ema.start + new_ema.length > start + length { + let r_ema = new_ema.split(start + length)?; + return Ok((Some(new_ema), Some(r_ema))); + } else { + return Ok((Some(new_ema), None)); + } + } else { + if self.start + self.length > start + length { + let new_ema = self.split(start + length)?; + return Ok((None, Some(new_ema))); + } else { + return Ok((None, None)); + } + } + } + + // 这里存在一个问题,如果是reserve ema node, 没有eaccept map怎么办 + /// Alloc the reserve / committed / vitual memory indeed + pub fn alloc(&mut self) -> SgxResult { + if self.alloc_flags.contains(AllocFlags::RESERVED) { + return Ok(()); + } + + // COMMIT_ON_DEMAND and COMMIT_NOW both need to mmap memory in urts + perm::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags)?; + + if self.alloc_flags.contains(AllocFlags::COMMIT_NOW) { + let grow_up: bool = if self.alloc_flags.contains(AllocFlags::GROWSDOWN) { + false + } else { + true + }; + self.eaccept(self.start, self.length, grow_up)?; + // set eaccept map full + match &mut self.eaccept_map { + Some(map) => { + map.set_full(); + } + None => { + // COMMIT_NOW must have eaccept_map + return Err(SgxStatus::Unexpected); + } + } + } else { + // clear eaccept map + match &mut self.eaccept_map { + Some(map) => { + map.clear(); + } + None => { + // COMMIT_NOW must have eaccept_map + return Err(SgxStatus::Unexpected); + } + } + } + return Ok(()); + } + + /// do eaccept for targeted EPC page + /// similiar to "apply_epc_pages(addr: usize, count: usize)" / intel emm do_commit() + /// do not change eaccept map + fn eaccept(&self, start: usize, length: usize, grow_up: bool) -> SgxResult { + let info = PageInfo { + typ: self.info.typ, + prot: self.info.prot | ProtFlags::PENDING, + }; + + let pages = PageRange::new(start, length / crate::arch::SE_PAGE_SIZE, info)?; + + if grow_up { + pages.accept_backward() + } else { + pages.accept_forward() + } + } + + /// ema_do_commit + pub fn commit(&mut self, start: usize, length: usize) -> SgxResult { + ensure!( + length != 0 + && (length % crate::arch::SE_PAGE_SIZE) == 0 + && start >= self.start + && start + length <= self.start + self.length, + SgxStatus::InvalidParameter + ); + + let info = PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, + }; + + let pages = PageRange::new(start, length / crate::arch::SE_PAGE_SIZE, info)?; + + // page index for parsing start address + let init_idx = (start - self.start) >> crate::arch::SE_PAGE_SHIFT; + let map = self.eaccept_map.as_mut().unwrap(); + + for (idx, page) in pages.iter().enumerate() { + let page_idx = idx + init_idx; + if map.get(page_idx) { + continue; + } else { + page.accept()?; + map.set(page_idx, true); + } + } + return Ok(()); + } + + /// uncommit EPC page + pub fn uncommit(&mut self, start: usize, length: usize, prot: ProtFlags) -> SgxResult { + // need READ for trimming + ensure!(self.info.prot != ProtFlags::NONE && self.eaccept_map.is_some(), + SgxStatus::InvalidParameter); + + if self.alloc_flags.contains(AllocFlags::RESERVED) { + return Ok(()); + } + + let trim_info = PageInfo { + typ: PageType::Trim, + prot: ProtFlags::MODIFIED, + }; + + let map = self.eaccept_map.as_mut().unwrap(); + let mut start = start; + let end: usize = start + length; + + // TODO: optimized with [u8] slice + while start < end { + let mut block_start = start; + while block_start < end { + let pos = (block_start - self.start) >> crate::arch::SE_PAGE_SHIFT; + if map.get(pos) { + break; + } else { + block_start += crate::arch::SE_PAGE_SIZE; + } + } + + if block_start == end { + break; + } + + let mut block_end = block_start + crate::arch::SE_PAGE_SIZE; + while block_end < end { + let pos = (block_end - self.start) >> crate::arch::SE_PAGE_SHIFT; + if map.get(pos) { + block_end += crate::arch::SE_PAGE_SIZE; + } else { + break; + } + } + + let block_length = block_end - block_start; + perm::modify_ocall(block_start, block_length, + PageInfo { + typ: self.info.typ, + prot, + }, + PageInfo { + typ: PageType::Trim, + prot, + }, + )?; + + let pages = PageRange::new( + block_start, + block_length / crate::arch::SE_PAGE_SIZE, + trim_info + )?; + + let init_idx = (block_start - self.start) >> crate::arch::SE_PAGE_SHIFT; + for (idx, page) in pages.iter().enumerate() { + page.accept()?; + let pos = idx + init_idx; + map.set(pos, false); + } + + // eaccept trim notify + perm::modify_ocall(block_start, block_length, + PageInfo { + typ: PageType::Trim, + prot, + }, + PageInfo { + typ: PageType::Trim, + prot, + }, + )?; + start = block_end; + } + Ok(()) + } + + pub fn modify_perm(&mut self, new_prot: ProtFlags) -> SgxResult { + if self.info.prot == new_prot { + return Ok(()); + } + + if SysFeatures::get().version() == Version::Sdk2_0 { + perm::modify_ocall( + self.start, + self.length, + self.info, + PageInfo { + typ: self.info.typ, + prot: new_prot, + }, + )?; + } + + let info = PageInfo { + typ: PageType::Reg, + prot: new_prot | ProtFlags::PR, + }; + + let pages = PageRange::new(self.start, self.length / crate::arch::SE_PAGE_SIZE, info)?; + + for page in pages.iter() { + // If new_prot is the subset of self.info.prot, no need to apply modpe. + // So we can't use new_prot != self.info.prot as determination + if (new_prot | self.info.prot) != self.info.prot { + page.modpe()?; + } + + // new permission is RWX, no EMODPR needed in untrusted part, hence no + // EACCEPT + if (new_prot & (ProtFlags::W | ProtFlags::X)) != (ProtFlags::W | ProtFlags::X) { + page.accept()?; + } + } + + self.info = PageInfo { + typ: self.info.typ, + prot: new_prot, + }; + + if new_prot == ProtFlags::NONE && SysFeatures::get().version() == Version::Sdk2_0 { + perm::modify_ocall( + self.start, + self.length, + PageInfo { + typ: self.info.typ, + prot: ProtFlags::NONE, + }, + PageInfo { + typ: self.info.typ, + prot: ProtFlags::NONE, + }, + )?; + } + + Ok(()) + } + + pub fn dealloc(&mut self) -> SgxResult { + if self.alloc_flags.contains(AllocFlags::RESERVED) { + return Ok(()); + } + + if self.info.prot == ProtFlags::NONE { + self.modify_perm(ProtFlags::R)?; + } + self.uncommit(self.start, self.length, ProtFlags::NONE)?; + Ok(()) + } + + pub fn aligned_end(&self, align: usize) -> usize { + let curr_end = self.start + self.length; + round_to!(curr_end, align) + } + + pub fn start(&self) -> usize { + self.start + } + + // get and set attributes + pub fn set_flags(flags: AllocFlags) -> SgxResult<()> { + todo!() + } + pub fn set_prot(info: PageInfo) -> SgxResult<()> { + todo!() + } + fn flags() -> AllocFlags { + todo!() + } + fn info(&self) -> PageInfo { + self.info + } + fn handler(&self) -> Option { + self.handler + } +} + +// +// intrusive_adapter!(pub RegEmaAda = Box, ResAlloc>: EMA { link: LinkedListLink }); + +// regular ema adapter +intrusive_adapter!(pub RegEmaAda = Box>: EMA { link: LinkedListLink }); + +// reserve ema adapter +intrusive_adapter!(pub ResEmaAda = Box>: EMA { link: LinkedListLink }); + diff --git a/sgx_trts/src/emm/emalist.rs b/sgx_trts/src/emm/emalist.rs new file mode 100644 index 000000000..de026ac83 --- /dev/null +++ b/sgx_trts/src/emm/emalist.rs @@ -0,0 +1,31 @@ +// emas: LinkedList, + + + + +// 其实ema list倒也不需要,我们可以有个init的user range +// pub struct EmaList { +// // intrusive linked list of reserve ema node for EMM +// emm: LinkedList, +// // intrusive linked list of regular ema node for User +// user: LinkedList, +// } + +// pub enum EmaType { +// Emm, +// User, +// } + +// impl EmaList { + +// pub fn new() -> Self { +// Self { +// emm: LinkedList::new(ResEmaAda::new()), +// user: LinkedList::new(RegEmaAda::new()), +// } +// } + +// pub fn emm_insert(&mut self, ema: Box, ResAlloc>) { + +// } +// } \ No newline at end of file diff --git a/sgx_trts/src/emm/flags.rs b/sgx_trts/src/emm/flags.rs new file mode 100644 index 000000000..c116667ca --- /dev/null +++ b/sgx_trts/src/emm/flags.rs @@ -0,0 +1,82 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +// 感觉这里可以优化一下的,因为EMA_RESERVED,EMA_COMMIT_NOW,EMA_COMMIT_ON_DEMAND其实是个enum。 +// 可以or | EMA_SYSTEM EMA_GROWSDOWN EMA_GROWSUP 组成的enum。 +use bitflags::bitflags; +use sgx_types::error::{SgxResult, SgxStatus}; + +bitflags! { + // 用bitflags的话,在ema输入的时候可能存在RESERVED & COMMIT_NOW 需要check一下 + pub struct AllocFlags: u32 { + const RESERVED = 0b0000_0001; + const COMMIT_NOW = 0b0000_0010; + const COMMIT_ON_DEMAND = 0b0000_0100; + const SYSTEM = 0b0001_0000; + const GROWSDOWN = 0x0010_0000; + const GROWSUP = 0x0100_0000; + } +} + +impl AllocFlags { + pub fn try_from(value: u32) -> SgxResult { + match value { + 0b0001_0001 => Ok(Self::RESERVED | Self::SYSTEM), + 0b0010_0001 => Ok(Self::RESERVED | Self::GROWSDOWN), + 0b0100_0001 => Ok(Self::RESERVED | Self::COMMIT_ON_DEMAND), + 0b0001_0010 => Ok(Self::COMMIT_NOW | Self::SYSTEM), + 0b0010_0010 => Ok(Self::COMMIT_NOW | Self::GROWSDOWN), + 0b0100_0010 => Ok(Self::COMMIT_NOW | Self::COMMIT_ON_DEMAND), + 0b0001_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::SYSTEM), + 0b0010_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::GROWSDOWN), + 0b0100_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::COMMIT_ON_DEMAND), + _ => Err(SgxStatus::InvalidParameter), + } + } +} + +// bitflags! { +// #[derive(Default)] +// pub struct SiFlags: u32 { +// const NONE = 0; +// const READ = 1 << 0; +// const WRITE = 1 << 1; +// const EXEC = 1 << 2; +// const READ_WRITE = Self::READ.bits | Self::WRITE.bits; +// const READ_EXEC = Self::READ.bits | Self::EXEC.bits; +// const READ_WRITE_EXEC = Self::READ.bits | Self::WRITE.bits | Self::EXEC.bits; +// } +// } + +// bitflags! { +// #[derive(Default)] +// pub struct PageType: u32 { +// const NONE = 0; +// const REG = 1 << 0; +// const TCS = 1 << 1; +// const TRIM = 1 << 2; +// // 相比于sdk,少了一个va +// } +// } + +// #[derive(Clone)] +// // Memory protection info +// #[repr(C)] +// pub struct ProtInfo { +// pub si_flags: SiFlags, +// pub page_type: PageType, +// } diff --git a/sgx_trts/src/emm/interior.rs b/sgx_trts/src/emm/interior.rs new file mode 100644 index 000000000..daca9dd47 --- /dev/null +++ b/sgx_trts/src/emm/interior.rs @@ -0,0 +1,242 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +use buddy_system_allocator::LockedHeap; +use intrusive_collections::intrusive_adapter; +use intrusive_collections::{LinkedList, LinkedListLink}; + +use alloc::boxed::Box; +use core::alloc::Layout; +use core::ffi::c_void; +use core::mem::transmute; +use core::mem::MaybeUninit; +use core::ptr::NonNull; +use spin::{Mutex, Once}; + +use sgx_types::error::{SgxResult, SgxStatus}; +use sgx_types::types::ProtectPerm; + +use crate::emm::ema::EMA; +use crate::emm::user::{USER_RANGE, self, is_within_user_range}; +use crate::enclave::is_within_enclave; + +use super::ema::ResEmaAda; + +const STATIC_MEM_SIZE: usize = 65536; + +/// first level: static memory +static STATIC: LockedHeap<32> = LockedHeap::empty(); + +static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; + +pub fn init() { + unsafe { + STATIC + .lock() + .init(STATIC_MEM.as_ptr() as usize, STATIC_MEM_SIZE); + } +} + +/// second level: reserve memory +/// +static RES_ALLOCATOR: Once = Once::new(); + +pub fn init_res() { + // res_allocator需要在meta_allocator之后初始化 + RES_ALLOCATOR.call_once(|| { + Mutex::new(Reserve::new(1024)); + }); +} + +// mm_reserve +struct Chunk { + pub base: usize, + pub size: usize, + pub used: usize, + link: LinkedListLink, // intrusive linkedlist +} + +intrusive_adapter!(ChunkAda = Box: Chunk { link: LinkedListLink }); +// let linkedlist = LinkedList::new(ResChunk_Adapter::new()); + +// mm_reserve +struct Block { + size: usize, + link: LinkedListLink, // intrusive linkedlist +} +// 或许在某些情况里也不需要link。 + +intrusive_adapter!(BlockAda = Box: Block { link: LinkedListLink }); + +pub struct Reserve { + // 这些list是block list,每个block用于存放如 ema meta / bitmap meta / bitmap data + exact_blocks: [LinkedList; 256], + large_blocks: LinkedList, + + // chunks 这个结构体是存放于reserve EMA分配的reserve内存 + chunks: LinkedList, + emas: LinkedList, + + // statistics + allocated: usize, + total: usize, +} + +impl Reserve { + /// Create an empty heap + pub fn new(size: usize) -> Self { + // unsafe { + // self.add_reserve(size); + // } + let exact_blocks: [LinkedList; 256] = { + let mut exact_blocks: [MaybeUninit>; 256] = + MaybeUninit::uninit_array(); + for block in &mut exact_blocks { + block.write(LinkedList::new(BlockAda::new())); + } + unsafe { transmute(exact_blocks) } + }; + + Self { + exact_blocks, + large_blocks: LinkedList::new(BlockAda::new()), + chunks: LinkedList::new(ChunkAda::new()), + emas: LinkedList::new(ResEmaAda::new()), + allocated: 0, + total: 0, + } + } + pub fn alloc(&mut self, layout: Layout) -> Result, ()> { + // // 先check是否内存是否不够了,如果不够了就掉用add_reserve + // // 从空闲区域分配一块内存,这块内存头部有个block header,记录使用的bytes + // // 随后,把这块block链入对应链表 + // static threshold = 512*1024; // 0.5MB + // if self.allocated + layout.size() + threshold > self.total { + // self.add_reserve(2*threshold); + // } + + // // search available region + // if layout.size() < 256 { + // let exact_block_list = exact_blocks[layout.size()-1]; + // if !exact_block_list.is_empty() { + // let block: Box = exact_block_list.pop_front().unwrap(); + // let ptr = unsafe { + // block.as_mut_ptr() - mem::size_of::(); + // } + // let addr = std::ptr::NonNull::::new(ptr as *mut u8).unwrap(); + // return addr; + // } + // } else { + // // similar operation in large blocks + // } + + // // no available region in free blocks + // let chunk = self.chunks.iter().find( + // |&chunk| (chunk.size - chunk.used) > layout.size() + // ); + // if let chunk = Some(chunk) { + // let ptr = chunk.base + chunk.used; + // chunk.used += layout.size(); + // let addr = std::ptr::NonNull::::new(ptr as *mut u8).unwrap(); + // return addr; + // } else { + // // self.add_reserve + // // self.alloc() + // } + todo!() + } + pub fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + // // 先通过ptr前面的block知道这个ptr的长度是多少 + // if size < 256 { + // // 将当前的ptr塞回队列 + // } else { + // // similar operation in large blocks + // } + todo!() + } + pub unsafe fn add_reserve(&mut self, size: usize) { + // // 分配一个EMA + // let reserve_ema: EMA = EMA::new(size); + // reserve_ema.alloc(size); + // self.emas.push(reserve_ema); + // // 将mm_res写入reserve_ema分配的EMA的首部 + // let chunk: ResChunk = ResChunk::new(); + // unsafe { + // let res_mem_ptr = reserve_ema.alloc().unwrap().as_mut_ptr(); + // std::ptr::write(res_mem_ptr as *mut ResChunk, chunk); + // let res_node = Box::from_raw(res_mem_ptr as *mut MM_Res ); + // // let new_mm_res = std::ptr::read(metadata_ptr as *const ResChunk); + // self.mm_reserve_list.push(res_node); + // } + todo!() + } + + // Find a free space of size at least 'size' bytes in reserve region, + // return the start address + fn find_free_region(&mut self, len: usize, align: usize) -> SgxResult { + let user_range = USER_RANGE.get().unwrap(); + let user_base = user_range.start; + let user_end = user_range.end; + + // no ema in list + if self.emas.is_empty() { + let mut addr = 0; + + if user_base >= len { + addr = trim_to!(user_base - len, align); + if is_within_enclave(addr as *const u8, len) { + return Ok(addr); + } + } else { + addr = round_to!(user_end, align); + if is_within_enclave(addr as *const u8, len) { + return Ok(addr); + } + } + return Err(SgxStatus::InvalidParameter); + } + + + let mut cursor = self.emas.cursor_mut(); + while !cursor.is_null() { + let curr_end = cursor.get() + .map(|ema| ema.aligned_end(align)).unwrap(); + + cursor.move_next(); + if cursor.is_null() { + break; + } + + let next_start = cursor.get() + .map(|ema| ema.start()).unwrap(); + + if curr_end < next_start { + let free_size = next_start - curr_end; + // 这里或许得用is_within_rts + if free_size < len && is_within_enclave(curr_end as *const u8, len){ + return Ok(curr_end); + } + } + cursor.move_next(); + } + + + todo!() + } +} + +const reserve_init_size: usize = 65536; diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs new file mode 100644 index 000000000..23aab2511 --- /dev/null +++ b/sgx_trts/src/emm/mod.rs @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +pub(crate) mod alloc; +pub(crate) mod bitmap; +pub(crate) mod ema; +pub(crate) mod flags; +#[cfg(not(any(feature = "sim", feature = "hyper")))] +pub(crate) mod interior; +pub(crate) mod user; diff --git a/sgx_trts/src/emm/user.rs b/sgx_trts/src/emm/user.rs new file mode 100644 index 000000000..b8876744f --- /dev/null +++ b/sgx_trts/src/emm/user.rs @@ -0,0 +1,96 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +use super::ema::{RegEmaAda, EMA}; +use crate::emm::interior::Reserve; +use crate::enclave::MmLayout; +use alloc::boxed::Box; +use alloc::sync::Arc; +use spin::{Once, Mutex}; +use core::alloc::Layout; +use core::ffi::c_void; +use core::ptr::NonNull; +use intrusive_collections::intrusive_adapter; +use intrusive_collections::{LinkedList, LinkedListLink}; +use sgx_types::error::{SgxResult, SgxStatus}; + +#[derive(Clone, Copy)] +pub struct UserRange { + pub start: usize, + pub end: usize, +} + +pub static USER_RANGE: Once = Once::new(); + +pub fn init_range(start: usize, end: usize) { + // init + *USER_RANGE.call_once(|| { + UserRange { + start, + end, + } + }); +} + +pub fn is_within_user_range(start: usize, len: usize) -> bool { + let end = if len > 0 { + if let Some(end) = start.checked_add(len - 1) { + end + } else { + return false; + } + } else { + start + }; + let base = MmLayout::elrange_base(); + + (start <= end) && (start >= base) && (end < base + MmLayout::elrange_size()) +} + +pub struct UserMem { + emas: LinkedList, + + // statistics + allocated: usize, + total: usize, +} + +impl UserMem { + pub fn new() -> Self { + Self { + emas: LinkedList::new(RegEmaAda::new()), + allocated: 0, + total: 0, + } + } + // fn split(ema: Box) -> SgxResult<()>{ + // todo!() + // } + // fn merge(ema1: Box, ema2: Box) + // -> SgxResult<()> { + // todo!() + // } + pub fn alloc(&mut self, layout: Layout) -> Result, ()> { + todo!() + } + pub fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + todo!() + } + pub fn commit(&mut self, layout: Layout) -> Result, ()> { + todo!() + } +} diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs index 84cb59690..56e1fcbeb 100644 --- a/sgx_trts/src/lib.rs +++ b/sgx_trts/src/lib.rs @@ -30,6 +30,8 @@ #![feature(nonnull_slice_from_raw_parts)] #![feature(ptr_internals)] #![feature(thread_local)] +#![feature(trait_alias)] +#![feature(new_uninit)] #![cfg_attr(feature = "sim", feature(unchecked_math))] #![allow(clippy::missing_safety_doc)] #![allow(dead_code)] @@ -60,6 +62,8 @@ mod version; mod xsave; pub mod capi; +pub mod edmm; +pub mod emm; #[cfg(not(any(feature = "sim", feature = "hyper")))] pub mod aexnotify; From 81f2da59a882fd711f6c455b80ccfc98106ccbc7 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Sun, 2 Jul 2023 20:26:49 +0800 Subject: [PATCH 02/20] Implement interior memory range management --- sgx_trts/Cargo.toml | 3 +- sgx_trts/src/edmm/epc.rs | 7 +- sgx_trts/src/emm/alloc.rs | 4 +- sgx_trts/src/emm/bitmap.rs | 8 +- sgx_trts/src/emm/ema.rs | 109 +++++++++---- sgx_trts/src/emm/flags.rs | 36 +++-- sgx_trts/src/emm/interior.rs | 302 +++++++++++++++++++++++++++++++---- sgx_trts/src/emm/user.rs | 47 ++++-- sgx_trts/src/lib.rs | 1 + 9 files changed, 413 insertions(+), 104 deletions(-) diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml index d1e2cb4e2..41abd2450 100644 --- a/sgx_trts/Cargo.toml +++ b/sgx_trts/Cargo.toml @@ -39,7 +39,8 @@ hyper = ["sgx_types/hyper"] sgx_types = { path = "../sgx_types" } sgx_crypto_sys = { path = "../sgx_crypto/sgx_crypto_sys" } sgx_tlibc_sys = { path = "../sgx_libc/sgx_tlibc_sys" } -intrusive-collections = "0.9.5" + +intrusive-collections = { git = "https://github.com/ClawSeven/intrusive-rs.git", rev = "3db5618" } buddy_system_allocator = "0.9.0" spin = "0.9.4" bitflags = "1.3" diff --git a/sgx_trts/src/edmm/epc.rs b/sgx_trts/src/edmm/epc.rs index 2465a4ce0..a1117d446 100644 --- a/sgx_trts/src/edmm/epc.rs +++ b/sgx_trts/src/edmm/epc.rs @@ -26,11 +26,14 @@ impl_enum! { #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PageType { - Secs = 0, + // Secs = 0, + None = 0, Tcs = 1, Reg = 2, - Va = 3, + // Va = 3, Trim = 4, + Frist = 5, + Rest = 6, } } diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index 30e1d7008..a3793ae42 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -2,7 +2,7 @@ use core::alloc::{AllocError, Allocator, Layout}; use core::ptr::NonNull; /// alloc layout memory from Reserve region -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct ResAlloc; unsafe impl Allocator for ResAlloc { @@ -16,7 +16,7 @@ unsafe impl Allocator for ResAlloc { } } -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct StaticAlloc; unsafe impl Allocator for StaticAlloc { diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index 5a7e1e370..2acd58e82 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -99,10 +99,10 @@ impl BitArray { break; } } - true_range.push((start,end)); + true_range.push((start, end)); } - return true_range; + return true_range; } /// Set the value of the bit at a given index. @@ -155,6 +155,4 @@ impl BitArray { } } - - -// FIXME: add more unit test \ No newline at end of file +// FIXME: add more unit test diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index cee7e1516..163cd09e7 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -34,14 +34,10 @@ use crate::trts::Version; use crate::veh::{ExceptionHandler, ExceptionInfo}; use super::alloc::ResAlloc; +use super::alloc::StaticAlloc; use super::bitmap::BitArray; use super::flags::AllocFlags; -// pub struct Box(_, _) -// where -// A: Allocator, -// T: ?Sized; - #[repr(C)] #[derive(Clone)] pub struct EMA @@ -81,6 +77,7 @@ where ) -> SgxResult { // check flags' eligibility AllocFlags::try_from(alloc_flags.bits())?; + if start != 0 && length != 0 && is_within_enclave(start as *const u8, length) @@ -103,38 +100,33 @@ where } } - // Returns a newly allocated ema in charging of the memory in the range [addr, len). - // After the call, the original ema will be left containing the elements [0, addr) + // Returns a newly allocated ema in charging of the memory in the range [addr, len). + // After the call, the original ema will be left containing the elements [0, addr) // with its previous capacity unchanged. - pub fn split(&mut self, addr: usize) -> SgxResult,A>> { + pub fn split(&mut self, addr: usize) -> SgxResult, A>> { let l_start = self.start; let l_length = addr - l_start; let r_start = addr; let r_length = (self.start + self.length) - addr; - let new_bitarray = match &mut self.eaccept_map{ + let new_bitarray = match &mut self.eaccept_map { Some(bitarray) => { let pos = (addr - self.start) >> crate::arch::SE_PAGE_SHIFT; // split self.eaccept_map Some(bitarray.split(pos)?) } - None => { - None - } + None => None, }; - + // 这里之后可以优化 // 1. self.clone() 会把原有的bitmap重新alloc并复制一份,但其实clone之后这里是None即可 // 2. 使用Box::new_in 会把 self.clone() 这部分在栈上的数据再拷贝一份到Box新申请的内存区域 - let mut new_ema: Box,A> = Box::new_in( - self.clone(), - self.alloc.clone() - ); + let mut new_ema: Box, A> = Box::new_in(self.clone(), self.alloc.clone()); self.start = l_start; self.length = l_length; - + new_ema.start = r_start; new_ema.length = r_length; new_ema.eaccept_map = new_bitarray; @@ -145,7 +137,11 @@ where // If the previous ema is divided into three parts -> (left ema, middle ema, right ema), return (middle ema, right ema). // If the previous ema is divided into two parts -> (left ema, right ema) // end split: return (None, right ema), start split: return (left ema, None) - fn split_into_three(&mut self, start: usize, length: usize) -> SgxResult<(Option,A>>, Option,A>>)> { + fn split_into_three( + &mut self, + start: usize, + length: usize, + ) -> SgxResult<(Option, A>>, Option, A>>)> { if start > self.start { let mut new_ema = self.split(start)?; if new_ema.start + new_ema.length > start + length { @@ -224,6 +220,28 @@ where } } + // Attension, return EACCES SgxStatus may be more appropriate + pub fn commit_check(&self) -> SgxResult { + if self.info.prot.intersects(ProtFlags::R | ProtFlags::W) { + return Err(SgxStatus::InvalidParameter); + } + + if self.info.typ != PageType::Reg { + return Err(SgxStatus::InvalidParameter); + } + + if self.alloc_flags.contains(AllocFlags::RESERVED) { + return Err(SgxStatus::InvalidParameter); + } + + Ok(()) + } + + /// commit all the memory in this ema + pub fn commit_self(&mut self) -> SgxResult { + self.commit(self.start, self.length) + } + /// ema_do_commit pub fn commit(&mut self, start: usize, length: usize) -> SgxResult { ensure!( @@ -260,8 +278,10 @@ where /// uncommit EPC page pub fn uncommit(&mut self, start: usize, length: usize, prot: ProtFlags) -> SgxResult { // need READ for trimming - ensure!(self.info.prot != ProtFlags::NONE && self.eaccept_map.is_some(), - SgxStatus::InvalidParameter); + ensure!( + self.info.prot != ProtFlags::NONE && self.eaccept_map.is_some(), + SgxStatus::InvalidParameter + ); if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); @@ -303,21 +323,23 @@ where } let block_length = block_end - block_start; - perm::modify_ocall(block_start, block_length, - PageInfo { + perm::modify_ocall( + block_start, + block_length, + PageInfo { typ: self.info.typ, prot, }, - PageInfo { + PageInfo { typ: PageType::Trim, prot, }, )?; let pages = PageRange::new( - block_start, - block_length / crate::arch::SE_PAGE_SIZE, - trim_info + block_start, + block_length / crate::arch::SE_PAGE_SIZE, + trim_info, )?; let init_idx = (block_start - self.start) >> crate::arch::SE_PAGE_SHIFT; @@ -328,12 +350,14 @@ where } // eaccept trim notify - perm::modify_ocall(block_start, block_length, - PageInfo { + perm::modify_ocall( + block_start, + block_length, + PageInfo { typ: PageType::Trim, prot, }, - PageInfo { + PageInfo { typ: PageType::Trim, prot, }, @@ -401,7 +425,7 @@ where )?; } - Ok(()) + Ok(()) } pub fn dealloc(&mut self) -> SgxResult { @@ -421,10 +445,26 @@ where round_to!(curr_end, align) } + pub fn end(&self) -> usize { + self.start + self.length + } + pub fn start(&self) -> usize { self.start } + pub fn len(&self) -> usize { + self.length + } + + pub fn lower_than_addr(&self, addr: usize) -> bool { + self.end() <= addr + } + + pub fn higher_than_addr(&self, addr: usize) -> bool { + self.start >= addr + } + // get and set attributes pub fn set_flags(flags: AllocFlags) -> SgxResult<()> { todo!() @@ -443,12 +483,11 @@ where } } -// +// // intrusive_adapter!(pub RegEmaAda = Box, ResAlloc>: EMA { link: LinkedListLink }); // regular ema adapter -intrusive_adapter!(pub RegEmaAda = Box>: EMA { link: LinkedListLink }); +intrusive_adapter!(pub RegEmaAda = ResAlloc, Box, ResAlloc>: EMA { link: LinkedListLink }); // reserve ema adapter -intrusive_adapter!(pub ResEmaAda = Box>: EMA { link: LinkedListLink }); - +intrusive_adapter!(pub ResEmaAda = StaticAlloc, Box, StaticAlloc>: EMA { link: LinkedListLink }); diff --git a/sgx_trts/src/emm/flags.rs b/sgx_trts/src/emm/flags.rs index c116667ca..bd003e90d 100644 --- a/sgx_trts/src/emm/flags.rs +++ b/sgx_trts/src/emm/flags.rs @@ -23,27 +23,33 @@ use sgx_types::error::{SgxResult, SgxStatus}; bitflags! { // 用bitflags的话,在ema输入的时候可能存在RESERVED & COMMIT_NOW 需要check一下 pub struct AllocFlags: u32 { - const RESERVED = 0b0000_0001; - const COMMIT_NOW = 0b0000_0010; - const COMMIT_ON_DEMAND = 0b0000_0100; - const SYSTEM = 0b0001_0000; - const GROWSDOWN = 0x0010_0000; - const GROWSUP = 0x0100_0000; + const RESERVED = 0b0001; + const COMMIT_NOW = 0b0010; + const COMMIT_ON_DEMAND = 0b0100; + const GROWSDOWN = 0b00010000; + const GROWSUP = 0b00100000; + const FIXED = 0b01000000; } } impl AllocFlags { pub fn try_from(value: u32) -> SgxResult { match value { - 0b0001_0001 => Ok(Self::RESERVED | Self::SYSTEM), - 0b0010_0001 => Ok(Self::RESERVED | Self::GROWSDOWN), - 0b0100_0001 => Ok(Self::RESERVED | Self::COMMIT_ON_DEMAND), - 0b0001_0010 => Ok(Self::COMMIT_NOW | Self::SYSTEM), - 0b0010_0010 => Ok(Self::COMMIT_NOW | Self::GROWSDOWN), - 0b0100_0010 => Ok(Self::COMMIT_NOW | Self::COMMIT_ON_DEMAND), - 0b0001_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::SYSTEM), - 0b0010_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::GROWSDOWN), - 0b0100_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::COMMIT_ON_DEMAND), + 0b0000_0001 => Ok(Self::RESERVED), + 0b0000_0010 => Ok(Self::COMMIT_NOW), + 0b0000_0100 => Ok(Self::COMMIT_ON_DEMAND), + 0b0001_0000 => Ok(Self::GROWSDOWN), + 0b0010_0000 => Ok(Self::GROWSUP), + 0b0100_0000 => Ok(Self::FIXED), + 0b0001_0001 => Ok(Self::RESERVED | Self::GROWSDOWN), + 0b0010_0001 => Ok(Self::RESERVED | Self::GROWSUP), + 0b0100_0001 => Ok(Self::RESERVED | Self::FIXED), + 0b0001_0010 => Ok(Self::COMMIT_NOW | Self::GROWSDOWN), + 0b0010_0010 => Ok(Self::COMMIT_NOW | Self::GROWSUP), + 0b0100_0010 => Ok(Self::COMMIT_NOW | Self::FIXED), + 0b0001_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::GROWSDOWN), + 0b0010_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::GROWSUP), + 0b0100_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::FIXED), _ => Err(SgxStatus::InvalidParameter), } } diff --git a/sgx_trts/src/emm/interior.rs b/sgx_trts/src/emm/interior.rs index daca9dd47..e114f6b74 100644 --- a/sgx_trts/src/emm/interior.rs +++ b/sgx_trts/src/emm/interior.rs @@ -17,8 +17,14 @@ use buddy_system_allocator::LockedHeap; use intrusive_collections::intrusive_adapter; +use intrusive_collections::linked_list::CursorMut; +use intrusive_collections::UnsafeRef; use intrusive_collections::{LinkedList, LinkedListLink}; +use crate::edmm::{PageInfo, PageType, ProtFlags}; +use crate::emm::alloc::StaticAlloc; +use crate::veh::{ExceptionHandler, ExceptionInfo}; +use alloc::alloc::Global; use alloc::boxed::Box; use core::alloc::Layout; use core::ffi::c_void; @@ -30,17 +36,19 @@ use spin::{Mutex, Once}; use sgx_types::error::{SgxResult, SgxStatus}; use sgx_types::types::ProtectPerm; +use crate::emm::alloc::ResAlloc; use crate::emm::ema::EMA; -use crate::emm::user::{USER_RANGE, self, is_within_user_range}; +use crate::emm::user::{self, is_within_rts_range, is_within_user_range, USER_RANGE}; use crate::enclave::is_within_enclave; use super::ema::ResEmaAda; +use super::flags::AllocFlags; const STATIC_MEM_SIZE: usize = 65536; /// first level: static memory static STATIC: LockedHeap<32> = LockedHeap::empty(); - + static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; pub fn init() { @@ -64,13 +72,13 @@ pub fn init_res() { // mm_reserve struct Chunk { - pub base: usize, - pub size: usize, - pub used: usize, + base: usize, + size: usize, + used: usize, link: LinkedListLink, // intrusive linkedlist } -intrusive_adapter!(ChunkAda = Box: Chunk { link: LinkedListLink }); +intrusive_adapter!(ChunkAda = Global, UnsafeRef: Chunk { link: LinkedListLink }); // let linkedlist = LinkedList::new(ResChunk_Adapter::new()); // mm_reserve @@ -78,9 +86,8 @@ struct Block { size: usize, link: LinkedListLink, // intrusive linkedlist } -// 或许在某些情况里也不需要link。 -intrusive_adapter!(BlockAda = Box: Block { link: LinkedListLink }); +intrusive_adapter!(BlockAda = Global, UnsafeRef: Block { link: LinkedListLink }); pub struct Reserve { // 这些list是block list,每个block用于存放如 ema meta / bitmap meta / bitmap data @@ -89,6 +96,8 @@ pub struct Reserve { // chunks 这个结构体是存放于reserve EMA分配的reserve内存 chunks: LinkedList, + // compared to intel emm using user range to store ema meta, + // we use rts range to store ema node emas: LinkedList, // statistics @@ -185,57 +194,286 @@ impl Reserve { todo!() } + // Not considering concurrency and lock + // TODO: carefull examination !! + fn alloc_inner( + &mut self, + addr: Option, + size: usize, + flags: AllocFlags, + ) -> SgxResult { + let info = if flags.contains(AllocFlags::RESERVED) { + PageInfo { + prot: ProtFlags::NONE, + typ: PageType::None, + } + } else { + PageInfo { + prot: ProtFlags::R | ProtFlags::W, + typ: PageType::Reg, + } + }; + + let align_flag = 12; + let align_mask: usize = (1 << align_flag) - 1; + if (addr.unwrap_or(0) & align_mask) != 0 { + return Err(SgxStatus::InvalidParameter); + } + + if addr.is_some() { + let addr = addr.unwrap(); + let is_fixed_alloc = flags.contains(AllocFlags::FIXED); + let range = self.search_ema_range(addr, addr + size, false); + + match range { + // exist in emas list + Ok(_) => { + // TODO: ema realloc from reserve + if is_fixed_alloc { + // FIXME: return EEXIST + return Err(SgxStatus::InvalidParameter); + } + } + // not exist in emas list + Err(_) => { + let next_ema = self.find_free_region_at(addr, size); + if next_ema.is_ok() && is_fixed_alloc { + return Err(SgxStatus::InvalidParameter); + } + } + }; + }; + + let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag)?; + + let mut new_ema = Box::, StaticAlloc>::new_in( + EMA::::new(free_addr, size, flags, info, None, None, StaticAlloc)?, + StaticAlloc, + ); + new_ema.alloc()?; + next_ema.insert_before(new_ema); + return Ok(free_addr); + } + + // Not considering concurrency and lock + // TODO: carefull examination !! + fn commit_inner(&mut self, addr: usize, size: usize) -> SgxResult { + let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, true)?; + let start_ema_ptr = cursor.get().unwrap() as *const EMA; + + // check ema can commit + let mut count = ema_num; + while count != 0 { + cursor.get().unwrap().commit_check()?; + cursor.move_next(); + count -= 1; + } + + let mut cursor = unsafe { self.emas.cursor_mut_from_ptr(start_ema_ptr) }; + + count = ema_num; + while count != 0 { + unsafe { cursor.get_mut().unwrap().commit_self()? }; + cursor.move_next(); + count -= 1; + } + + Ok(()) + } + + // search for a range of nodes containing addresses within [start, end) + // 'ema_begin' will hold the fist ema that has address higher than /euqal to + // 'start' 'ema_end' will hold the node immediately follow the last ema that has + // address lower than / equal to 'end' + // return ema_end and ema num + fn search_ema_range( + &mut self, + start: usize, + end: usize, + continuous: bool, + ) -> SgxResult<(CursorMut<'_, ResEmaAda>, usize)> { + let mut cursor = self.emas.front(); + + while !cursor.is_null() && cursor.get().unwrap().lower_than_addr(start) { + cursor.move_next(); + } + + if cursor.is_null() || cursor.get().unwrap().higher_than_addr(end) { + return Err(SgxStatus::InvalidParameter); + } + + let mut curr_ema = cursor.get().unwrap(); + + let mut start_ema_ptr = curr_ema as *const EMA; + let mut emas_num = 0; + let mut prev_end = curr_ema.start(); + + while !cursor.is_null() && !cursor.get().unwrap().higher_than_addr(end) { + curr_ema = cursor.get().unwrap(); + // If continuity is required, there should + // be no gaps in the specified range in the emas list. + if continuous && prev_end != curr_ema.start() { + return Err(SgxStatus::InvalidParameter); + } + + emas_num += 1; + prev_end = curr_ema.end(); + cursor.move_next(); + } + + drop(cursor); + + let mut end_ema_ptr = curr_ema as *const EMA; + + // Found the overlapping emas with range [start, end) + // needs to splitting emas + + // Spliting start ema + let mut start_cursor = unsafe { self.emas.cursor_mut_from_ptr(start_ema_ptr) }; + + let curr_ema = unsafe { start_cursor.get_mut().unwrap() }; + let ema_start = curr_ema.start(); + + // Problem may exist, need to check!! + if ema_start < start { + let right_ema = curr_ema.split(start).unwrap(); + start_cursor.insert_after(right_ema); + start_cursor.move_next(); + start_ema_ptr = start_cursor.get().unwrap() as *const EMA; + } + + if emas_num == 1 { + end_ema_ptr = start_ema_ptr; + } + drop(start_cursor); + + // Spliting end ema + let mut end_cursor = unsafe { self.emas.cursor_mut_from_ptr(end_ema_ptr) }; + + let end_ema = unsafe { end_cursor.get_mut().unwrap() }; + let ema_end = end_ema.end(); + + if ema_end > end { + let right_ema = end_ema.split(end).unwrap(); + end_cursor.insert_after(right_ema); + } + drop(end_cursor); + + // Recover start ema and return it as range + let start_cursor = unsafe { self.emas.cursor_mut_from_ptr(start_ema_ptr) }; + + return Ok((start_cursor, emas_num)); + } + + // Find a free space at addr with 'len' bytes in reserve region, + // the request space mustn't intersect with existed ema node. + // If success, return the next ema cursor. + fn find_free_region_at( + &mut self, + addr: usize, + len: usize, + ) -> SgxResult> { + if !is_within_enclave(addr as *const u8, len) || !is_within_rts_range(addr, len) { + return Err(SgxStatus::InvalidParameter); + } + + let mut cursor: CursorMut<'_, ResEmaAda> = self.emas.front_mut(); + while !cursor.is_null() { + let start_curr = cursor.get().map(|ema| ema.start()).unwrap(); + let end_curr = start_curr + cursor.get().map(|ema| ema.len()).unwrap(); + if start_curr >= addr + len { + return Ok(cursor); + } + + if addr >= end_curr { + cursor.move_next(); + } else { + break; + } + } + + // means addr is larger than the end of the last ema node + if cursor.is_null() { + return Ok(cursor); + } + + return Err(SgxStatus::InvalidParameter); + } + // Find a free space of size at least 'size' bytes in reserve region, // return the start address - fn find_free_region(&mut self, len: usize, align: usize) -> SgxResult { + fn find_free_region( + &mut self, + len: usize, + align: usize, + ) -> SgxResult<(usize, CursorMut<'_, ResEmaAda>)> { let user_range = USER_RANGE.get().unwrap(); let user_base = user_range.start; let user_end = user_range.end; - // no ema in list - if self.emas.is_empty() { - let mut addr = 0; + let mut addr = 0; + let mut cursor: CursorMut<'_, ResEmaAda> = self.emas.front_mut(); + // no ema in list + if cursor.is_null() { if user_base >= len { addr = trim_to!(user_base - len, align); if is_within_enclave(addr as *const u8, len) { - return Ok(addr); + return Ok((addr, cursor)); } } else { addr = round_to!(user_end, align); if is_within_enclave(addr as *const u8, len) { - return Ok(addr); + return Ok((addr, cursor)); } } return Err(SgxStatus::InvalidParameter); } + let mut cursor_next = cursor.peek_next(); - let mut cursor = self.emas.cursor_mut(); - while !cursor.is_null() { - let curr_end = cursor.get() - .map(|ema| ema.aligned_end(align)).unwrap(); + // ema is_null means pointing to the Null object, not means this ema is empty + while !cursor_next.is_null() { + let curr_end = cursor.get().map(|ema| ema.aligned_end(align)).unwrap(); - cursor.move_next(); - if cursor.is_null() { - break; - } - - let next_start = cursor.get() - .map(|ema| ema.start()).unwrap(); - - if curr_end < next_start { - let free_size = next_start - curr_end; - // 这里或许得用is_within_rts - if free_size < len && is_within_enclave(curr_end as *const u8, len){ - return Ok(curr_end); + let start_next = cursor_next.get().map(|ema| ema.start()).unwrap(); + + if curr_end < start_next { + let free_size = start_next - curr_end; + if free_size < len && is_within_rts_range(curr_end, len) { + cursor.move_next(); + return Ok((curr_end, cursor)); } } cursor.move_next(); + cursor_next = cursor.peek_next(); } + addr = cursor.get().map(|ema| ema.aligned_end(align)).unwrap(); - todo!() + if is_within_enclave(addr as *const u8, len) && is_within_rts_range(addr, len) { + cursor.move_next(); + return Ok((addr, cursor)); + } + + // Cursor moves to emas->front_mut. + // Firstly cursor moves to None, then moves to linkedlist head + cursor.move_next(); + cursor.move_next(); + + // Back to the first ema to check rts region before user region + let start_first = cursor.get().map(|ema| ema.start()).unwrap(); + if start_first < len { + return Err(SgxStatus::InvalidParameter); + } + + addr = trim_to!(start_first, align); + + if is_within_enclave(addr as *const u8, len) && is_within_rts_range(addr, len) { + return Ok((addr, cursor)); + } + + Err(SgxStatus::InvalidParameter) } } diff --git a/sgx_trts/src/emm/user.rs b/sgx_trts/src/emm/user.rs index b8876744f..ebd2dabc9 100644 --- a/sgx_trts/src/emm/user.rs +++ b/sgx_trts/src/emm/user.rs @@ -15,18 +15,18 @@ // specific language governing permissions and limitations // under the License.. -use super::ema::{RegEmaAda, EMA}; +use super::ema::{ResEmaAda, EMA}; use crate::emm::interior::Reserve; use crate::enclave::MmLayout; use alloc::boxed::Box; use alloc::sync::Arc; -use spin::{Once, Mutex}; use core::alloc::Layout; use core::ffi::c_void; use core::ptr::NonNull; use intrusive_collections::intrusive_adapter; use intrusive_collections::{LinkedList, LinkedListLink}; use sgx_types::error::{SgxResult, SgxStatus}; +use spin::{Mutex, Once}; #[derive(Clone, Copy)] pub struct UserRange { @@ -34,16 +34,37 @@ pub struct UserRange { pub end: usize, } +impl UserRange { + fn start(&self) -> usize { + self.start + } + fn end(&self) -> usize { + self.end + } +} + pub static USER_RANGE: Once = Once::new(); pub fn init_range(start: usize, end: usize) { - // init - *USER_RANGE.call_once(|| { - UserRange { - start, - end, + // init + let _ = *USER_RANGE.call_once(|| UserRange { start, end }); +} + +pub fn is_within_rts_range(start: usize, len: usize) -> bool { + let end = if len > 0 { + if let Some(end) = start.checked_add(len - 1) { + end + } else { + return false; } - }); + } else { + start + }; + let user_range = USER_RANGE.get().unwrap(); + let user_start = user_range.start(); + let user_end = user_range.end(); + + (start >= user_end) || (end < user_start) } pub fn is_within_user_range(start: usize, len: usize) -> bool { @@ -56,13 +77,15 @@ pub fn is_within_user_range(start: usize, len: usize) -> bool { } else { start }; - let base = MmLayout::elrange_base(); + let user_range = USER_RANGE.get().unwrap(); + let user_start = user_range.start(); + let user_end = user_range.end(); - (start <= end) && (start >= base) && (end < base + MmLayout::elrange_size()) + (start <= end) && (start >= user_start) && (end < user_end) } pub struct UserMem { - emas: LinkedList, + emas: LinkedList, // statistics allocated: usize, @@ -72,7 +95,7 @@ pub struct UserMem { impl UserMem { pub fn new() -> Self { Self { - emas: LinkedList::new(RegEmaAda::new()), + emas: LinkedList::new(ResEmaAda::new()), allocated: 0, total: 0, } diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs index 56e1fcbeb..9c8d687c9 100644 --- a/sgx_trts/src/lib.rs +++ b/sgx_trts/src/lib.rs @@ -36,6 +36,7 @@ #![allow(clippy::missing_safety_doc)] #![allow(dead_code)] #![allow(non_camel_case_types)] +#![feature(linked_list_cursors)] #[cfg(all(feature = "sim", feature = "hyper"))] compile_error!("feature \"sim\" and feature \"hyper\" cannot be enabled at the same time"); From f08478acc52847e868e729d8eb8f9a5e208fc653 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Tue, 18 Jul 2023 10:44:18 +0800 Subject: [PATCH 03/20] Implement EMM draft code --- sgx_trts/Cargo.toml | 3 +- sgx_trts/src/emm/alloc.rs | 23 +- sgx_trts/src/emm/bitmap.rs | 135 ++++--- sgx_trts/src/emm/ema.rs | 220 ++++++++---- sgx_trts/src/emm/emalist.rs | 31 -- sgx_trts/src/emm/flags.rs | 35 -- sgx_trts/src/emm/interior.rs | 661 +++++++++++++++++------------------ sgx_trts/src/emm/mod.rs | 1 + sgx_trts/src/emm/range.rs | 587 +++++++++++++++++++++++++++++++ sgx_trts/src/emm/user.rs | 47 +-- sgx_trts/src/lib.rs | 1 + 11 files changed, 1148 insertions(+), 596 deletions(-) delete mode 100644 sgx_trts/src/emm/emalist.rs create mode 100644 sgx_trts/src/emm/range.rs diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml index 41abd2450..ebed5c748 100644 --- a/sgx_trts/Cargo.toml +++ b/sgx_trts/Cargo.toml @@ -40,7 +40,8 @@ sgx_types = { path = "../sgx_types" } sgx_crypto_sys = { path = "../sgx_crypto/sgx_crypto_sys" } sgx_tlibc_sys = { path = "../sgx_libc/sgx_tlibc_sys" } -intrusive-collections = { git = "https://github.com/ClawSeven/intrusive-rs.git", rev = "3db5618" } +intrusive-collections = { git = "https://github.com/ClawSeven/intrusive-rs.git", rev = "6d34cd7" } +# intrusive-collections = { git = "https://github.com/ClawSeven/intrusive-rs.git", rev = "3db5618" } buddy_system_allocator = "0.9.0" spin = "0.9.4" bitflags = "1.3" diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index a3793ae42..9adad6f1c 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -1,18 +1,27 @@ use core::alloc::{AllocError, Allocator, Layout}; use core::ptr::NonNull; +use crate::emm::interior::{RES_ALLOCATOR, STATIC}; + /// alloc layout memory from Reserve region #[derive(Clone, Copy)] pub struct ResAlloc; unsafe impl Allocator for ResAlloc { fn allocate(&self, layout: Layout) -> Result, AllocError> { - todo!() + let size = layout.size(); + RES_ALLOCATOR + .get() + .unwrap() + .lock() + .emalloc(size) + .map(|addr| NonNull::slice_from_raw_parts(NonNull::new(addr as *mut u8).unwrap(), size)) + .map_err(|_| AllocError) } #[inline] - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - todo!() + unsafe fn deallocate(&self, ptr: NonNull, _layout: Layout) { + RES_ALLOCATOR.get().unwrap().lock().efree(ptr.addr().get()) } } @@ -21,11 +30,15 @@ pub struct StaticAlloc; unsafe impl Allocator for StaticAlloc { fn allocate(&self, layout: Layout) -> Result, AllocError> { - todo!() + STATIC + .lock() + .alloc(layout) + .map(|addr| NonNull::slice_from_raw_parts(addr, layout.size())) + .map_err(|_| AllocError) } #[inline] unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - todo!() + STATIC.lock().dealloc(ptr, layout); } } diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index 2acd58e82..d78b2f527 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -16,28 +16,43 @@ // under the License.. use alloc::boxed::Box; use alloc::vec; -use alloc::vec::Vec; use core::alloc::Allocator; +use core::alloc::Layout; use core::clone::Clone; +use core::ptr::NonNull; use sgx_types::error::SgxResult; use sgx_types::error::SgxStatus; -// box 能否 #[repr(C)] +use super::alloc::ResAlloc; +use super::alloc::StaticAlloc; +use super::interior::Alloc; + +#[repr(C)] #[derive(Clone)] -pub struct BitArray { - pub bits: usize, - pub bytes: usize, - pub data: Box<[u8], A>, // temporariy use ResAlloc - alloc: A, +pub struct BitArray { + bits: usize, + bytes: usize, + data: *mut u8, + alloc: Alloc, } -impl BitArray { +impl BitArray { /// Init BitArray in Reserve memory with all zeros. - pub fn new_in(bits: usize, alloc: A) -> SgxResult { + pub fn new(bits: usize, alloc: Alloc) -> SgxResult { let bytes = (bits + 7) / 8; // FIXME: return error if out of memory - let data: Box<[u8], A> = vec::from_elem_in(0_u8, bytes, alloc.clone()).into_boxed_slice(); + let data = match alloc { + Alloc::Reserve => { + let data = vec::from_elem_in(0_u8, bytes, ResAlloc).into_boxed_slice(); + Box::into_raw(data) as *mut u8 + } + Alloc::Static => { + let data = vec::from_elem_in(0_u8, bytes, StaticAlloc).into_boxed_slice(); + Box::into_raw(data) as *mut u8 + } + }; + Ok(Self { bits, bytes, @@ -52,7 +67,18 @@ impl BitArray { let byte_index = index / 8; let bit_index = index % 8; let bit_mask = 1 << bit_index; - (self.data.get(byte_index).unwrap() & bit_mask) != 0 + let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; + (data.get(byte_index).unwrap() & bit_mask) != 0 + } + + // check whether each bit set true + pub fn all_true(&self) -> bool { + for pos in 0..self.bits { + if !self.get(pos) { + return false; + } + } + true } // Set the value of the bit at a given index. @@ -61,7 +87,8 @@ impl BitArray { let bit_index = index % 8; let bit_mask = 1 << bit_index; - let data = self.data.as_mut(); + let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; + if value { data[byte_index] |= bit_mask; } else { @@ -69,42 +96,6 @@ impl BitArray { } } - // return chunk range with all true, Vec<[start, end)> - pub fn true_range(&self) -> Vec<(usize, usize), A> { - let mut true_range: Vec<(usize, usize), A> = Vec::new_in(self.alloc.clone()); - - let start: usize = 0; - let end: usize = self.bits; - - // TODO: optimized with [u8] slice - while start < end { - let mut block_start = start; - while block_start < end { - if self.get(block_start) { - break; - } else { - block_start += 1; - } - } - - if block_start == end { - break; - } - - let mut block_end = block_start + 1; - while block_end < end { - if self.get(block_end) { - block_end += 1; - } else { - break; - } - } - true_range.push((start, end)); - } - - return true_range; - } - /// Set the value of the bit at a given index. /// The range includes [0, index). pub fn set_until(&mut self, index: usize, value: bool) { @@ -114,17 +105,20 @@ impl BitArray { /// Set the value of the bit at a given index. /// The range includes [0, index). pub fn set_full(&mut self) { - self.data.fill(0xFF); + let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; + data.fill(0xFF); } /// Clear all the bits pub fn clear(&mut self) { - self.data.fill(0); + let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; + data.fill(0); } // split current bit array into left and right bit array // return right bit array - pub fn split(&mut self, pos: usize) -> SgxResult> { + // TODO: more check + pub fn split(&mut self, pos: usize) -> SgxResult { ensure!(pos > 0 && pos < self.bits, SgxStatus::InvalidParameter); let byte_index = pos / 8; @@ -137,16 +131,20 @@ impl BitArray { let r_bits = self.bits - l_bits; let r_bytes = (r_bits + 7) / 8; - let mut r_array = Self::new_in(r_bits, self.alloc.clone())?; + let r_array = Self::new(r_bits, self.alloc.clone())?; + + let r_data = unsafe { core::slice::from_raw_parts_mut(r_array.data, r_array.bytes) }; - for (idx, item) in r_array.data[..(r_bytes - 1)].iter_mut().enumerate() { + let l_data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; + + for (idx, item) in r_data[..(r_bytes - 1)].iter_mut().enumerate() { // current byte index in previous bit_array let curr_idx = idx + byte_index; - let low_bits = self.data[curr_idx] >> bit_index; - let high_bits = self.data[curr_idx + 1] << (8 - bit_index); + let low_bits = l_data[curr_idx] >> bit_index; + let high_bits = l_data[curr_idx + 1] << (8 - bit_index); *item = high_bits | low_bits; } - r_array.data[r_bytes - 1] = self.data[self.bytes - 1] >> bit_index; + r_data[r_bytes - 1] = l_data[self.bytes - 1] >> bit_index; self.bits = l_bits; self.bytes = l_bytes; @@ -155,4 +153,29 @@ impl BitArray { } } +impl Drop for BitArray { + fn drop(&mut self) { + match self.alloc { + Alloc::Reserve => { + // for interior allocator, layout is redundant + let fake_layout: Layout = Layout::new::(); + unsafe { + let data_ptr = NonNull::new_unchecked(self.data); + ResAlloc.deallocate(data_ptr, fake_layout); + } + } + Alloc::Static => { + // for interior allocator, layout is redundant + // If the bitmap is splitted, the size of + // allocated layout is not recorded in bitmap struct + let fake_layout: Layout = Layout::new::(); + unsafe { + let data_ptr = NonNull::new_unchecked(self.data); + StaticAlloc.deallocate(data_ptr, fake_layout); + } + } + } + } +} + // FIXME: add more unit test diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index 163cd09e7..db540e9dd 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -15,17 +15,17 @@ // specific language governing permissions and limitations // under the License.. -use core::alloc::Allocator; - -use crate::arch::Secinfo; -use crate::arch::SecinfoFlags; +use crate::arch::SE_PAGE_SHIFT; +use crate::arch::SE_PAGE_SIZE; use crate::edmm::perm; use crate::edmm::PageRange; use crate::edmm::{PageInfo, PageType, ProtFlags}; use crate::enclave::is_within_enclave; +use alloc::alloc::Global; use alloc::boxed::Box; use intrusive_collections::intrusive_adapter; use intrusive_collections::LinkedListLink; +use intrusive_collections::UnsafeRef; use sgx_types::error::SgxResult; use sgx_types::error::SgxStatus; @@ -37,13 +37,11 @@ use super::alloc::ResAlloc; use super::alloc::StaticAlloc; use super::bitmap::BitArray; use super::flags::AllocFlags; +use super::interior::Alloc; #[repr(C)] #[derive(Clone)] -pub struct EMA -where - A: Allocator + Clone, -{ +pub struct EMA { // starting address, page aligned start: usize, // bytes, or page may be more available @@ -51,20 +49,21 @@ where alloc_flags: AllocFlags, info: PageInfo, // bitmap for EACCEPT status - eaccept_map: Option>, - // custom PF handler (for EACCEPTCOPY use) + eaccept_map: Option, + // custom PF handler handler: Option, // private data for handler priv_data: Option<*mut ExceptionInfo>, - alloc: A, + alloc: Alloc, // intrusive linkedlist link: LinkedListLink, } -impl EMA -where - A: Allocator + Clone, -{ +// TODO: remove send and sync +unsafe impl Send for EMA {} +unsafe impl Sync for EMA {} + +impl EMA { // start address must be page aligned pub fn new( start: usize, @@ -73,7 +72,7 @@ where info: PageInfo, handler: Option, priv_data: Option<*mut ExceptionInfo>, - alloc: A, + alloc: Alloc, ) -> SgxResult { // check flags' eligibility AllocFlags::try_from(alloc_flags.bits())?; @@ -100,10 +99,10 @@ where } } - // Returns a newly allocated ema in charging of the memory in the range [addr, len). - // After the call, the original ema will be left containing the elements [0, addr) + // Returns a newly allocated ema in charging of the memory in the range [addr, addr + len). + // After the call, the original ema will be left containing the elements [start, addr) // with its previous capacity unchanged. - pub fn split(&mut self, addr: usize) -> SgxResult, A>> { + pub fn split(&mut self, addr: usize) -> SgxResult<*mut EMA> { let l_start = self.start; let l_length = addr - l_start; @@ -119,54 +118,38 @@ where None => None, }; - // 这里之后可以优化 - // 1. self.clone() 会把原有的bitmap重新alloc并复制一份,但其实clone之后这里是None即可 - // 2. 使用Box::new_in 会把 self.clone() 这部分在栈上的数据再拷贝一份到Box新申请的内存区域 - let mut new_ema: Box, A> = Box::new_in(self.clone(), self.alloc.clone()); + let new_ema: *mut EMA = match self.alloc { + Alloc::Reserve => { + let mut ema = Box::new_in(self.clone(), ResAlloc); + ema.start = r_start; + ema.length = r_length; + ema.eaccept_map = new_bitarray; + Box::into_raw(ema) + } + Alloc::Static => { + let mut ema = Box::new_in(self.clone(), StaticAlloc); + ema.start = r_start; + ema.length = r_length; + ema.eaccept_map = new_bitarray; + Box::into_raw(ema) + } + }; self.start = l_start; self.length = l_length; - new_ema.start = r_start; - new_ema.length = r_length; - new_ema.eaccept_map = new_bitarray; - return Ok(new_ema); } - // If the previous ema is divided into three parts -> (left ema, middle ema, right ema), return (middle ema, right ema). - // If the previous ema is divided into two parts -> (left ema, right ema) - // end split: return (None, right ema), start split: return (left ema, None) - fn split_into_three( - &mut self, - start: usize, - length: usize, - ) -> SgxResult<(Option, A>>, Option, A>>)> { - if start > self.start { - let mut new_ema = self.split(start)?; - if new_ema.start + new_ema.length > start + length { - let r_ema = new_ema.split(start + length)?; - return Ok((Some(new_ema), Some(r_ema))); - } else { - return Ok((Some(new_ema), None)); - } - } else { - if self.start + self.length > start + length { - let new_ema = self.split(start + length)?; - return Ok((None, Some(new_ema))); - } else { - return Ok((None, None)); - } - } - } - - // 这里存在一个问题,如果是reserve ema node, 没有eaccept map怎么办 + // FIXME: handling reserve ema node doesn't have ema eaccept /// Alloc the reserve / committed / vitual memory indeed pub fn alloc(&mut self) -> SgxResult { if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); } + // new self bitmap + // COMMIT_ON_DEMAND and COMMIT_NOW both need to mmap memory in urts perm::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags)?; @@ -275,13 +258,26 @@ where return Ok(()); } + pub fn uncommit_check(&self) -> SgxResult { + if self.alloc_flags.contains(AllocFlags::RESERVED) { + return Err(SgxStatus::InvalidParameter); + } + Ok(()) + } + + pub fn uncommit_self(&mut self) -> SgxResult { + let prot = self.info.prot; + if prot == ProtFlags::NONE { + self.modify_perm(ProtFlags::R)? + } + + self.uncommit(self.start, self.length, prot) + } + /// uncommit EPC page pub fn uncommit(&mut self, start: usize, length: usize, prot: ProtFlags) -> SgxResult { // need READ for trimming - ensure!( - self.info.prot != ProtFlags::NONE && self.eaccept_map.is_some(), - SgxStatus::InvalidParameter - ); + ensure!(self.eaccept_map.is_some(), SgxStatus::InvalidParameter); if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); @@ -367,6 +363,29 @@ where Ok(()) } + pub fn modify_perm_check(&self) -> SgxResult { + if self.info.typ != PageType::Reg { + return Err(SgxStatus::InvalidParameter); + } + + if self.alloc_flags.contains(AllocFlags::RESERVED) { + return Err(SgxStatus::InvalidParameter); + } + + match &self.eaccept_map { + Some(bitmap) => { + if !bitmap.all_true() { + return Err(SgxStatus::InvalidParameter); + } + } + None => { + return Err(SgxStatus::InvalidParameter); + } + } + + Ok(()) + } + pub fn modify_perm(&mut self, new_prot: ProtFlags) -> SgxResult { if self.info.prot == new_prot { return Ok(()); @@ -428,6 +447,69 @@ where Ok(()) } + pub fn change_to_tcs(&mut self) -> SgxResult { + // the ema has and only has one page + if self.length != SE_PAGE_SIZE { + return Err(SgxStatus::InvalidParameter); + } + + // page must be committed + if !self.is_page_committed(self.start) { + return Err(SgxStatus::InvalidParameter); + } + + let info = self.info; + + // page has been changed to tcs + if info.typ == PageType::Tcs { + return Ok(()); + } + + if (info.prot != (ProtFlags::R | ProtFlags::W)) || (info.typ != PageType::Reg) { + return Err(SgxStatus::InvalidParameter); + } + + perm::modify_ocall( + self.start, + self.length, + info, + PageInfo { + typ: PageType::Tcs, + prot: info.prot, + }, + )?; + + let eaccept_info = PageInfo { + typ: PageType::Tcs, + prot: ProtFlags::MODIFIED, + }; + + let pages = PageRange::new( + self.start, + self.length / crate::arch::SE_PAGE_SIZE, + eaccept_info, + )?; + + for page in pages.iter() { + page.accept()?; + } + + self.info = PageInfo { + typ: PageType::Tcs, + prot: ProtFlags::NONE, + }; + Ok(()) + } + + fn is_page_committed(&self, addr: usize) -> bool { + assert!(addr % SE_PAGE_SIZE == 0); + if self.eaccept_map.is_none() { + return false; + } + let pos = (addr - self.start) >> SE_PAGE_SHIFT; + self.eaccept_map.as_ref().unwrap().get(pos) + } + pub fn dealloc(&mut self) -> SgxResult { if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); @@ -465,15 +547,14 @@ where self.start >= addr } - // get and set attributes - pub fn set_flags(flags: AllocFlags) -> SgxResult<()> { - todo!() + pub fn set_flags(&mut self, flags: AllocFlags) { + self.alloc_flags = flags; } - pub fn set_prot(info: PageInfo) -> SgxResult<()> { - todo!() + pub fn set_prot(&mut self, info: PageInfo) { + self.info = info; } - fn flags() -> AllocFlags { - todo!() + fn flags(&self) -> AllocFlags { + self.alloc_flags } fn info(&self) -> PageInfo { self.info @@ -483,11 +564,4 @@ where } } -// -// intrusive_adapter!(pub RegEmaAda = Box, ResAlloc>: EMA { link: LinkedListLink }); - -// regular ema adapter -intrusive_adapter!(pub RegEmaAda = ResAlloc, Box, ResAlloc>: EMA { link: LinkedListLink }); - -// reserve ema adapter -intrusive_adapter!(pub ResEmaAda = StaticAlloc, Box, StaticAlloc>: EMA { link: LinkedListLink }); +intrusive_adapter!(pub EmaAda = UnsafeRef: EMA { link: LinkedListLink }); diff --git a/sgx_trts/src/emm/emalist.rs b/sgx_trts/src/emm/emalist.rs deleted file mode 100644 index de026ac83..000000000 --- a/sgx_trts/src/emm/emalist.rs +++ /dev/null @@ -1,31 +0,0 @@ -// emas: LinkedList, - - - - -// 其实ema list倒也不需要,我们可以有个init的user range -// pub struct EmaList { -// // intrusive linked list of reserve ema node for EMM -// emm: LinkedList, -// // intrusive linked list of regular ema node for User -// user: LinkedList, -// } - -// pub enum EmaType { -// Emm, -// User, -// } - -// impl EmaList { - -// pub fn new() -> Self { -// Self { -// emm: LinkedList::new(ResEmaAda::new()), -// user: LinkedList::new(RegEmaAda::new()), -// } -// } - -// pub fn emm_insert(&mut self, ema: Box, ResAlloc>) { - -// } -// } \ No newline at end of file diff --git a/sgx_trts/src/emm/flags.rs b/sgx_trts/src/emm/flags.rs index bd003e90d..1d278170c 100644 --- a/sgx_trts/src/emm/flags.rs +++ b/sgx_trts/src/emm/flags.rs @@ -15,13 +15,10 @@ // specific language governing permissions and limitations // under the License.. -// 感觉这里可以优化一下的,因为EMA_RESERVED,EMA_COMMIT_NOW,EMA_COMMIT_ON_DEMAND其实是个enum。 -// 可以or | EMA_SYSTEM EMA_GROWSDOWN EMA_GROWSUP 组成的enum。 use bitflags::bitflags; use sgx_types::error::{SgxResult, SgxStatus}; bitflags! { - // 用bitflags的话,在ema输入的时候可能存在RESERVED & COMMIT_NOW 需要check一下 pub struct AllocFlags: u32 { const RESERVED = 0b0001; const COMMIT_NOW = 0b0010; @@ -54,35 +51,3 @@ impl AllocFlags { } } } - -// bitflags! { -// #[derive(Default)] -// pub struct SiFlags: u32 { -// const NONE = 0; -// const READ = 1 << 0; -// const WRITE = 1 << 1; -// const EXEC = 1 << 2; -// const READ_WRITE = Self::READ.bits | Self::WRITE.bits; -// const READ_EXEC = Self::READ.bits | Self::EXEC.bits; -// const READ_WRITE_EXEC = Self::READ.bits | Self::WRITE.bits | Self::EXEC.bits; -// } -// } - -// bitflags! { -// #[derive(Default)] -// pub struct PageType: u32 { -// const NONE = 0; -// const REG = 1 << 0; -// const TCS = 1 << 1; -// const TRIM = 1 << 2; -// // 相比于sdk,少了一个va -// } -// } - -// #[derive(Clone)] -// // Memory protection info -// #[repr(C)] -// pub struct ProtInfo { -// pub si_flags: SiFlags, -// pub page_type: PageType, -// } diff --git a/sgx_trts/src/emm/interior.rs b/sgx_trts/src/emm/interior.rs index e114f6b74..4835a426c 100644 --- a/sgx_trts/src/emm/interior.rs +++ b/sgx_trts/src/emm/interior.rs @@ -17,41 +17,49 @@ use buddy_system_allocator::LockedHeap; use intrusive_collections::intrusive_adapter; -use intrusive_collections::linked_list::CursorMut; +use intrusive_collections::singly_linked_list::CursorMut; +use intrusive_collections::singly_linked_list::{Link, SinglyLinkedList}; use intrusive_collections::UnsafeRef; use intrusive_collections::{LinkedList, LinkedListLink}; -use crate::edmm::{PageInfo, PageType, ProtFlags}; -use crate::emm::alloc::StaticAlloc; -use crate::veh::{ExceptionHandler, ExceptionInfo}; -use alloc::alloc::Global; -use alloc::boxed::Box; -use core::alloc::Layout; -use core::ffi::c_void; +use crate::sync::SpinMutex; +use core::mem::size_of; use core::mem::transmute; use core::mem::MaybeUninit; -use core::ptr::NonNull; use spin::{Mutex, Once}; +use super::flags::AllocFlags; +use super::range::{RangeType, RM}; use sgx_types::error::{SgxResult, SgxStatus}; -use sgx_types::types::ProtectPerm; -use crate::emm::alloc::ResAlloc; -use crate::emm::ema::EMA; -use crate::emm::user::{self, is_within_rts_range, is_within_user_range, USER_RANGE}; -use crate::enclave::is_within_enclave; +// fixed static memory size +const STATIC_MEM_SIZE: usize = 65536; +// initial interior reserve memory size +const INIT_MEM_SIZE: usize = 65536; +// the size of guard for interior memory +const GUARD_SIZE: usize = 0x8000; +// this is enough for bit map of an 8T EMA +const MAX_EMALLOC_SIZE: usize = 0x10000000; -use super::ema::ResEmaAda; -use super::flags::AllocFlags; +const ALLOC_MASK: usize = 1; +const SIZE_MASK: usize = !(EXACT_MATCH_INCREMENT - 1); -const STATIC_MEM_SIZE: usize = 65536; +// the increment size for interior memory +static mut INCR_SIZE: usize = 65536; /// first level: static memory -static STATIC: LockedHeap<32> = LockedHeap::empty(); +pub static STATIC: LockedHeap<32> = LockedHeap::empty(); + +#[derive(Clone)] +#[repr(u8)] +pub enum Alloc { + Static, + Reserve, +} static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; -pub fn init() { +pub fn init_static_alloc() { unsafe { STATIC .lock() @@ -60,14 +68,20 @@ pub fn init() { } /// second level: reserve memory -/// -static RES_ALLOCATOR: Once = Once::new(); - -pub fn init_res() { - // res_allocator需要在meta_allocator之后初始化 - RES_ALLOCATOR.call_once(|| { - Mutex::new(Reserve::new(1024)); - }); +/// Some problem here! +// static RES_ALLOCATOR: Once> = Once::new(); +pub static RES_ALLOCATOR: Once> = Once::new(); +pub static GLOBAL_LOCK: Once> = Once::new(); + +pub fn init_global_lock() { + GLOBAL_LOCK.call_once(|| SpinMutex::new(())); +} + +pub fn init_reserve_alloc() -> SgxResult { + let reserve = Mutex::new(Reserve::new(1024)?); + // res_allocator need to be intialized after static_allocator + RES_ALLOCATOR.call_once(|| reserve); + Ok(()) } // mm_reserve @@ -75,30 +89,75 @@ struct Chunk { base: usize, size: usize, used: usize, - link: LinkedListLink, // intrusive linkedlist + link: Link, // singly intrusive linkedlist +} + +impl Chunk { + fn new(base: usize, size: usize) -> Self { + Self { + base, + size, + used: 0, + link: Link::new(), + } + } } -intrusive_adapter!(ChunkAda = Global, UnsafeRef: Chunk { link: LinkedListLink }); -// let linkedlist = LinkedList::new(ResChunk_Adapter::new()); +intrusive_adapter!(ChunkAda = UnsafeRef: Chunk { link: LinkedListLink }); -// mm_reserve -struct Block { +const NUM_EXACT_LIST: usize = 0x100; +const HEADER_SIZE: usize = size_of::(); +const EXACT_MATCH_INCREMENT: usize = 0x8; +const MIN_BLOCK_SIZE: usize = 0x10; +const MAX_EXACT_SIZE: usize = MIN_BLOCK_SIZE + EXACT_MATCH_INCREMENT * (NUM_EXACT_LIST - 1); + +enum Block { + Free(BlockFree), + Used(BlockUsed), +} + +// free block for allocationg exact size +#[repr(C)] +struct BlockFree { + size: usize, + link: LinkedListLink, // doubly intrusive linkedlist +} + +// used block for tracking allocated size and base address +#[repr(C)] +struct BlockUsed { size: usize, - link: LinkedListLink, // intrusive linkedlist + payload: usize, +} + +impl BlockFree { + fn new(size: usize) -> Self { + Self { + size, + link: LinkedListLink::new(), + } + } + + fn block_size(&self) -> usize { + self.size & SIZE_MASK + } +} + +impl BlockUsed { + fn new(size: usize) -> Self { + Self { size, payload: 0 } + } } -intrusive_adapter!(BlockAda = Global, UnsafeRef: Block { link: LinkedListLink }); +intrusive_adapter!(BlockFreeAda = UnsafeRef: BlockFree { link: LinkedListLink }); pub struct Reserve { - // 这些list是block list,每个block用于存放如 ema meta / bitmap meta / bitmap data - exact_blocks: [LinkedList; 256], - large_blocks: LinkedList, + // Each block manage an area of free memory + exact_blocks: [LinkedList; 256], + large_blocks: LinkedList, - // chunks 这个结构体是存放于reserve EMA分配的reserve内存 - chunks: LinkedList, - // compared to intel emm using user range to store ema meta, - // we use rts range to store ema node - emas: LinkedList, + // Each chunk manage an area of memory allocated by one EMA + chunks: SinglyLinkedList, // statistics allocated: usize, @@ -106,375 +165,279 @@ pub struct Reserve { } impl Reserve { - /// Create an empty heap - pub fn new(size: usize) -> Self { - // unsafe { - // self.add_reserve(size); - // } - let exact_blocks: [LinkedList; 256] = { - let mut exact_blocks: [MaybeUninit>; 256] = + pub fn new(size: usize) -> SgxResult { + let exact_blocks: [LinkedList; 256] = { + let mut exact_blocks: [MaybeUninit>; 256] = MaybeUninit::uninit_array(); for block in &mut exact_blocks { - block.write(LinkedList::new(BlockAda::new())); + block.write(LinkedList::new(BlockFreeAda::new())); } unsafe { transmute(exact_blocks) } }; - Self { + let mut reserve = Self { exact_blocks, - large_blocks: LinkedList::new(BlockAda::new()), - chunks: LinkedList::new(ChunkAda::new()), - emas: LinkedList::new(ResEmaAda::new()), + large_blocks: LinkedList::new(BlockFreeAda::new()), + chunks: SinglyLinkedList::new(ChunkAda::new()), allocated: 0, total: 0, + }; + unsafe { + reserve.add_reserve(size)?; } - } - pub fn alloc(&mut self, layout: Layout) -> Result, ()> { - // // 先check是否内存是否不够了,如果不够了就掉用add_reserve - // // 从空闲区域分配一块内存,这块内存头部有个block header,记录使用的bytes - // // 随后,把这块block链入对应链表 - // static threshold = 512*1024; // 0.5MB - // if self.allocated + layout.size() + threshold > self.total { - // self.add_reserve(2*threshold); - // } - - // // search available region - // if layout.size() < 256 { - // let exact_block_list = exact_blocks[layout.size()-1]; - // if !exact_block_list.is_empty() { - // let block: Box = exact_block_list.pop_front().unwrap(); - // let ptr = unsafe { - // block.as_mut_ptr() - mem::size_of::(); - // } - // let addr = std::ptr::NonNull::::new(ptr as *mut u8).unwrap(); - // return addr; - // } - // } else { - // // similar operation in large blocks - // } - - // // no available region in free blocks - // let chunk = self.chunks.iter().find( - // |&chunk| (chunk.size - chunk.used) > layout.size() - // ); - // if let chunk = Some(chunk) { - // let ptr = chunk.base + chunk.used; - // chunk.used += layout.size(); - // let addr = std::ptr::NonNull::::new(ptr as *mut u8).unwrap(); - // return addr; - // } else { - // // self.add_reserve - // // self.alloc() - // } - todo!() - } - pub fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - // // 先通过ptr前面的block知道这个ptr的长度是多少 - // if size < 256 { - // // 将当前的ptr塞回队列 - // } else { - // // similar operation in large blocks - // } - todo!() - } - pub unsafe fn add_reserve(&mut self, size: usize) { - // // 分配一个EMA - // let reserve_ema: EMA = EMA::new(size); - // reserve_ema.alloc(size); - // self.emas.push(reserve_ema); - // // 将mm_res写入reserve_ema分配的EMA的首部 - // let chunk: ResChunk = ResChunk::new(); - // unsafe { - // let res_mem_ptr = reserve_ema.alloc().unwrap().as_mut_ptr(); - // std::ptr::write(res_mem_ptr as *mut ResChunk, chunk); - // let res_node = Box::from_raw(res_mem_ptr as *mut MM_Res ); - // // let new_mm_res = std::ptr::read(metadata_ptr as *const ResChunk); - // self.mm_reserve_list.push(res_node); - // } - todo!() + Ok(reserve) } - // Not considering concurrency and lock - // TODO: carefull examination !! - fn alloc_inner( - &mut self, - addr: Option, - size: usize, - flags: AllocFlags, - ) -> SgxResult { - let info = if flags.contains(AllocFlags::RESERVED) { - PageInfo { - prot: ProtFlags::NONE, - typ: PageType::None, - } - } else { - PageInfo { - prot: ProtFlags::R | ProtFlags::W, - typ: PageType::Reg, - } - }; - - let align_flag = 12; - let align_mask: usize = (1 << align_flag) - 1; - if (addr.unwrap_or(0) & align_mask) != 0 { - return Err(SgxStatus::InvalidParameter); + fn get_free_block(&mut self, bsize: usize) -> Option> { + if bsize <= MAX_EXACT_SIZE { + return self.get_exact_block(bsize); } - if addr.is_some() { - let addr = addr.unwrap(); - let is_fixed_alloc = flags.contains(AllocFlags::FIXED); - let range = self.search_ema_range(addr, addr + size, false); - - match range { - // exist in emas list - Ok(_) => { - // TODO: ema realloc from reserve - if is_fixed_alloc { - // FIXME: return EEXIST - return Err(SgxStatus::InvalidParameter); - } - } - // not exist in emas list - Err(_) => { - let next_ema = self.find_free_region_at(addr, size); - if next_ema.is_ok() && is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); - } + // loop and find the most available large block + let list = &mut self.large_blocks; + let mut cursor = list.front_mut(); + let mut suit_block: Option<*const BlockFree> = None; + let mut suit_block_size = 0; + while !cursor.is_null() { + let curr_block = cursor.get().unwrap(); + if curr_block.size >= bsize { + if suit_block.is_none() { + suit_block = Some(curr_block as *const BlockFree); + suit_block_size = curr_block.size; + } else if suit_block_size > curr_block.size { + suit_block = Some(curr_block as *const BlockFree); + suit_block_size = curr_block.size; } - }; - }; - - let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag)?; - - let mut new_ema = Box::, StaticAlloc>::new_in( - EMA::::new(free_addr, size, flags, info, None, None, StaticAlloc)?, - StaticAlloc, - ); - new_ema.alloc()?; - next_ema.insert_before(new_ema); - return Ok(free_addr); - } - - // Not considering concurrency and lock - // TODO: carefull examination !! - fn commit_inner(&mut self, addr: usize, size: usize) -> SgxResult { - let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, true)?; - let start_ema_ptr = cursor.get().unwrap() as *const EMA; - - // check ema can commit - let mut count = ema_num; - while count != 0 { - cursor.get().unwrap().commit_check()?; + } cursor.move_next(); - count -= 1; } - let mut cursor = unsafe { self.emas.cursor_mut_from_ptr(start_ema_ptr) }; - - count = ema_num; - while count != 0 { - unsafe { cursor.get_mut().unwrap().commit_self()? }; - cursor.move_next(); - count -= 1; + if suit_block.is_none() { + return None; } - Ok(()) - } + let mut cursor = unsafe { list.cursor_mut_from_ptr(suit_block.unwrap()) }; + let suit_block = cursor.remove(); - // search for a range of nodes containing addresses within [start, end) - // 'ema_begin' will hold the fist ema that has address higher than /euqal to - // 'start' 'ema_end' will hold the node immediately follow the last ema that has - // address lower than / equal to 'end' - // return ema_end and ema num - fn search_ema_range( - &mut self, - start: usize, - end: usize, - continuous: bool, - ) -> SgxResult<(CursorMut<'_, ResEmaAda>, usize)> { - let mut cursor = self.emas.front(); + // TODO: split suit block + return suit_block; + } - while !cursor.is_null() && cursor.get().unwrap().lower_than_addr(start) { - cursor.move_next(); - } + fn get_exact_block(&mut self, bsize: usize) -> Option> { + let idx = self.get_list_idx(bsize); + let list = &mut self.exact_blocks[idx]; + list.pop_front() + } - if cursor.is_null() || cursor.get().unwrap().higher_than_addr(end) { - return Err(SgxStatus::InvalidParameter); + fn put_free_block(&mut self, block: UnsafeRef) { + let block_size = block.block_size(); + if block_size <= MAX_EXACT_SIZE { + // put block into list with exact block size + let idx = self.get_list_idx(block_size); + let list = &mut self.exact_blocks[idx]; + list.push_back(block); + } else { + // put block into list with large block size + let list = &mut self.large_blocks; + list.push_back(block); } + } - let mut curr_ema = cursor.get().unwrap(); - - let mut start_ema_ptr = curr_ema as *const EMA; - let mut emas_num = 0; - let mut prev_end = curr_ema.start(); - - while !cursor.is_null() && !cursor.get().unwrap().higher_than_addr(end) { - curr_ema = cursor.get().unwrap(); - // If continuity is required, there should - // be no gaps in the specified range in the emas list. - if continuous && prev_end != curr_ema.start() { - return Err(SgxStatus::InvalidParameter); - } + // merge next free block into this block + fn reconfigure_block(&self, _block: UnsafeRef) -> UnsafeRef { + todo!() + } - emas_num += 1; - prev_end = curr_ema.end(); - cursor.move_next(); + /// Obtain the list index for exact block size + fn get_list_idx(&self, size: usize) -> usize { + assert!(size % EXACT_MATCH_INCREMENT == 0); + if size < MIN_BLOCK_SIZE { + return 0; } + let idx = (size - MIN_BLOCK_SIZE) / EXACT_MATCH_INCREMENT; + assert!(idx < NUM_EXACT_LIST); + return idx; + } - drop(cursor); - - let mut end_ema_ptr = curr_ema as *const EMA; - - // Found the overlapping emas with range [start, end) - // needs to splitting emas + // Attention! If we need to clear the memory + fn block_to_payload(&self, block: UnsafeRef) -> usize { + let block_size = block.size; + let block_used = BlockUsed::new(block_size); + let ptr = UnsafeRef::into_raw(block) as *mut BlockUsed; + let payload_addr = unsafe { + ptr.write(block_used); + ptr.offset(HEADER_SIZE as isize) as usize + }; + return payload_addr; + } - // Spliting start ema - let mut start_cursor = unsafe { self.emas.cursor_mut_from_ptr(start_ema_ptr) }; + fn payload_to_block(&self, payload_addr: usize) -> UnsafeRef { + // payload shift to block_use + let payload_ptr = payload_addr as *const u8; + let block_used_ptr = + unsafe { payload_ptr.offset(-(HEADER_SIZE as isize)) as *mut BlockUsed }; - let curr_ema = unsafe { start_cursor.get_mut().unwrap() }; - let ema_start = curr_ema.start(); + let block_size = unsafe { block_used_ptr.read().size }; - // Problem may exist, need to check!! - if ema_start < start { - let right_ema = curr_ema.split(start).unwrap(); - start_cursor.insert_after(right_ema); - start_cursor.move_next(); - start_ema_ptr = start_cursor.get().unwrap() as *const EMA; + let block_free = BlockFree::new(block_size); + let ptr = block_used_ptr as *mut BlockFree; + unsafe { + ptr.write(block_free); + UnsafeRef::from_raw(ptr) } + } - if emas_num == 1 { - end_ema_ptr = start_ema_ptr; - } - drop(start_cursor); + pub fn emalloc(&mut self, size: usize) -> SgxResult { + let mut bsize = round_to!(size + HEADER_SIZE, EXACT_MATCH_INCREMENT); + bsize = bsize.max(MIN_BLOCK_SIZE); - // Spliting end ema - let mut end_cursor = unsafe { self.emas.cursor_mut_from_ptr(end_ema_ptr) }; + // find free block in lists + let mut block = self.get_free_block(bsize); - let end_ema = unsafe { end_cursor.get_mut().unwrap() }; - let ema_end = end_ema.end(); + match block { + Some(mut block) => { + let block_size = bsize | ALLOC_MASK; + block.size = block_size; + return Ok(self.block_to_payload(block)); + } + None => (), + }; - if ema_end > end { - let right_ema = end_ema.split(end).unwrap(); - end_cursor.insert_after(right_ema); + block = self.alloc_from_reserve(bsize); + if block.is_none() { + let chunk_size = size_of::(); + let new_reserve_size = round_to!(bsize + chunk_size, INIT_MEM_SIZE); + unsafe { self.add_reserve(new_reserve_size)? }; + block = self.alloc_from_reserve(bsize); + // should never happen + if block.is_none() { + return Err(SgxStatus::InvalidParameter); + } } - drop(end_cursor); - // Recover start ema and return it as range - let start_cursor = unsafe { self.emas.cursor_mut_from_ptr(start_ema_ptr) }; + let mut block = block.unwrap(); - return Ok((start_cursor, emas_num)); + block.size = bsize | ALLOC_MASK; + return Ok(self.block_to_payload(block)); } - // Find a free space at addr with 'len' bytes in reserve region, - // the request space mustn't intersect with existed ema node. - // If success, return the next ema cursor. - fn find_free_region_at( - &mut self, - addr: usize, - len: usize, - ) -> SgxResult> { - if !is_within_enclave(addr as *const u8, len) || !is_within_rts_range(addr, len) { - return Err(SgxStatus::InvalidParameter); - } - - let mut cursor: CursorMut<'_, ResEmaAda> = self.emas.front_mut(); + fn alloc_from_reserve(&mut self, bsize: usize) -> Option> { + let mut addr: usize = 0; + let mut cursor = self.chunks.front_mut(); while !cursor.is_null() { - let start_curr = cursor.get().map(|ema| ema.start()).unwrap(); - let end_curr = start_curr + cursor.get().map(|ema| ema.len()).unwrap(); - if start_curr >= addr + len { - return Ok(cursor); - } - - if addr >= end_curr { - cursor.move_next(); - } else { + let chunk = unsafe { cursor.get_mut().unwrap() }; + if chunk.size - chunk.used >= bsize { + addr = chunk.base + chunk.used; + chunk.used += bsize; break; } + cursor.move_next(); } - // means addr is larger than the end of the last ema node - if cursor.is_null() { - return Ok(cursor); + if addr == 0 { + return None; + } else { + let block = BlockFree::new(bsize); + let ptr = addr as *mut BlockFree; + let block = unsafe { + ptr.write(block); + UnsafeRef::from_raw(ptr) + }; + return Some(block); } - - return Err(SgxStatus::InvalidParameter); } - // Find a free space of size at least 'size' bytes in reserve region, - // return the start address - fn find_free_region( - &mut self, - len: usize, - align: usize, - ) -> SgxResult<(usize, CursorMut<'_, ResEmaAda>)> { - let user_range = USER_RANGE.get().unwrap(); - let user_base = user_range.start; - let user_end = user_range.end; - - let mut addr = 0; - - let mut cursor: CursorMut<'_, ResEmaAda> = self.emas.front_mut(); - // no ema in list - if cursor.is_null() { - if user_base >= len { - addr = trim_to!(user_base - len, align); - if is_within_enclave(addr as *const u8, len) { - return Ok((addr, cursor)); - } - } else { - addr = round_to!(user_end, align); - if is_within_enclave(addr as *const u8, len) { - return Ok((addr, cursor)); - } - } - return Err(SgxStatus::InvalidParameter); + pub fn efree(&mut self, payload_addr: usize) { + let block = self.payload_to_block(payload_addr); + let block_addr = block.as_ref() as *const BlockFree as usize; + let block_size = block.block_size(); + let block_end = block_addr + block_size; + let res = self.find_chunk_with_block(block_addr, block_size); + if res.is_err() { + panic!(); } + // reconfigure block + let mut cursor = res.unwrap(); + let chunk = unsafe { cursor.get_mut().unwrap() }; - let mut cursor_next = cursor.peek_next(); + if block_end - chunk.base == chunk.used { + chunk.used -= block.size; + } - // ema is_null means pointing to the Null object, not means this ema is empty - while !cursor_next.is_null() { - let curr_end = cursor.get().map(|ema| ema.aligned_end(align)).unwrap(); + // TODO: merge large block into reserve - let start_next = cursor_next.get().map(|ema| ema.start()).unwrap(); + self.put_free_block(block); + } - if curr_end < start_next { - let free_size = start_next - curr_end; - if free_size < len && is_within_rts_range(curr_end, len) { - cursor.move_next(); - return Ok((curr_end, cursor)); - } - } - cursor.move_next(); - cursor_next = cursor.peek_next(); + /// Adding the size of interior memory + /// rsize: memory increment + pub unsafe fn add_reserve(&mut self, rsize: usize) -> SgxResult { + // Here we alloc at least INIT_MEM_SIZE size, + // but commit rsize memory, the remaining memory is COMMIT_ON_DEMAND + let increment = INCR_SIZE.max(rsize); + let mut range_manage = RM.get().unwrap().lock(); + let base = range_manage.alloc( + None, + increment + 2 * GUARD_SIZE, + AllocFlags::RESERVED.bits() as usize, + None, + None, + RangeType::User, + Alloc::Static, + )?; + + let base = range_manage.alloc( + Some(base + GUARD_SIZE), + increment, + (AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED).bits() as usize, + None, + None, + RangeType::User, + Alloc::Static, + )?; + + range_manage.commit(base, rsize, RangeType::User)?; + drop(range_manage); + + unsafe { + self.write_chunk(base, increment); } - addr = cursor.get().map(|ema| ema.aligned_end(align)).unwrap(); + INCR_SIZE = INCR_SIZE * 2; + if INCR_SIZE > MAX_EMALLOC_SIZE { + INCR_SIZE = MAX_EMALLOC_SIZE + }; - if is_within_enclave(addr as *const u8, len) && is_within_rts_range(addr, len) { - cursor.move_next(); - return Ok((addr, cursor)); - } + Ok(()) + } - // Cursor moves to emas->front_mut. - // Firstly cursor moves to None, then moves to linkedlist head - cursor.move_next(); - cursor.move_next(); + unsafe fn write_chunk(&mut self, base: usize, size: usize) { + let chunk: Chunk = Chunk::new(base, size); + unsafe { + core::ptr::write(base as *mut Chunk, chunk); + let chunk_ref = UnsafeRef::from_raw(base as *const Chunk); + self.chunks.push_front(chunk_ref); + } + } - // Back to the first ema to check rts region before user region - let start_first = cursor.get().map(|ema| ema.start()).unwrap(); - if start_first < len { + // find the chunk including the specified block: fn find_used_in_reserve + fn find_chunk_with_block( + &mut self, + block_addr: usize, + block_size: usize, + ) -> SgxResult> { + if block_size == 0 { return Err(SgxStatus::InvalidParameter); } - - addr = trim_to!(start_first, align); - - if is_within_enclave(addr as *const u8, len) && is_within_rts_range(addr, len) { - return Ok((addr, cursor)); + let mut cursor = self.chunks.front_mut(); + while !cursor.is_null() { + let chunk = cursor.get().unwrap(); + if block_addr >= chunk.base && block_addr + block_size <= chunk.base + chunk.used { + return Ok(cursor); + } + cursor.move_next(); } - Err(SgxStatus::InvalidParameter) + return Err(SgxStatus::InvalidParameter); } } - -const reserve_init_size: usize = 65536; diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index 23aab2511..68fe33c7c 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -21,4 +21,5 @@ pub(crate) mod ema; pub(crate) mod flags; #[cfg(not(any(feature = "sim", feature = "hyper")))] pub(crate) mod interior; +pub(crate) mod range; pub(crate) mod user; diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs new file mode 100644 index 000000000..c1c0b8a78 --- /dev/null +++ b/sgx_trts/src/emm/range.rs @@ -0,0 +1,587 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +use crate::{ + arch::SE_PAGE_SIZE, + edmm::{PageInfo, PageType, ProtFlags}, + enclave::is_within_enclave, + veh::{ExceptionHandler, ExceptionInfo}, +}; +use alloc::boxed::Box; +use intrusive_collections::{linked_list::CursorMut, LinkedList, UnsafeRef}; +use sgx_types::error::{SgxResult, SgxStatus}; +use spin::{Mutex, Once}; + +use super::{ + alloc::{ResAlloc, StaticAlloc}, + ema::{EmaAda, EMA}, + flags::AllocFlags, + interior::{Alloc, GLOBAL_LOCK}, + user::{is_within_rts_range, is_within_user_range, USER_RANGE}, +}; + +const ALLOC_FLAGS_SHIFT: usize = 0; +const ALLOC_FLAGS_MASK: usize = 0xFF << ALLOC_FLAGS_SHIFT; + +const PAGE_TYPE_SHIFT: usize = 8; +const PAGE_TYPE_MASK: usize = 0xFF << PAGE_TYPE_SHIFT; + +const ALLIGNMENT_SHIFT: usize = 24; +const ALLIGNMENT_MASK: usize = 0xFF << ALLIGNMENT_SHIFT; + +pub static mut RM: Once> = Once::new(); + +pub fn init_range_manage() { + unsafe { + RM.call_once(|| Mutex::new(RangeManage::new())); + } +} + +pub struct RangeManage { + user: LinkedList, + rts: LinkedList, +} + +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RangeType { + Rts, + User, +} + +impl RangeManage { + pub fn new() -> Self { + Self { + user: LinkedList::new(EmaAda::new()), + rts: LinkedList::new(EmaAda::new()), + } + } + + // Not considering concurrency and lock + // TODO: carefull examination !! + pub fn alloc( + &mut self, + addr: Option, + size: usize, + flags: usize, + handler: Option, + priv_data: Option<*mut ExceptionInfo>, + typ: RangeType, + alloc: Alloc, + ) -> SgxResult { + let addr = addr.unwrap_or(0); + let alloc_flags = + AllocFlags::try_from(((flags & ALLOC_FLAGS_MASK) >> ALLOC_FLAGS_SHIFT) as u32)?; + let mut page_type = + match PageType::try_from(((flags & PAGE_TYPE_MASK) >> PAGE_TYPE_SHIFT) as u8) { + Ok(typ) => typ, + Err(_) => return Err(SgxStatus::InvalidParameter), + }; + + if page_type == PageType::None { + page_type = PageType::Reg; + } + + if (size % SE_PAGE_SIZE) > 0 { + return Err(SgxStatus::InvalidParameter); + } + + let mut align_flag: u8 = ((flags & ALLIGNMENT_MASK) >> ALLIGNMENT_SHIFT) as u8; + if align_flag == 0 { + align_flag = 12; + } + if align_flag < 12 { + return Err(SgxStatus::InvalidParameter); + } + let align_mask: usize = (1 << align_flag) - 1; + + if (addr & align_mask) > 0 { + return Err(SgxStatus::InvalidParameter); + } + + if (addr > 0) && !is_within_enclave(addr as *const u8, size) { + return Err(SgxStatus::InvalidParameter); + } + + let info = if alloc_flags.contains(AllocFlags::RESERVED) { + PageInfo { + prot: ProtFlags::NONE, + typ: PageType::None, + } + } else { + PageInfo { + prot: ProtFlags::R | ProtFlags::W, + typ: page_type, + } + }; + + if addr > 0 { + let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); + let range = self.search_ema_range(addr, addr + size, typ, false); + + match range { + // exist in emas list + Ok(_) => { + // TODO: ema realloc from reserve + // If this ema can be reallocated, call allocation + if is_fixed_alloc { + // FIXME: return EEXIST + return Err(SgxStatus::InvalidParameter); + } + } + // not exist in emas list + Err(_) => { + let next_ema = self.find_free_region_at(addr, size, typ); + // fixme: is_err + if next_ema.is_ok() && is_fixed_alloc { + return Err(SgxStatus::InvalidParameter); + } + } + }; + }; + + let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; + + let new_ema_ref = match alloc { + Alloc::Reserve => { + let mut new_ema = Box::::new_in( + EMA::new( + free_addr, + size, + alloc_flags, + info, + handler, + priv_data, + Alloc::Static, + )?, + ResAlloc, + ); + new_ema.alloc()?; + + unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } + } + Alloc::Static => { + let mut new_ema = Box::::new_in( + EMA::new( + free_addr, + size, + alloc_flags, + info, + handler, + priv_data, + Alloc::Static, + )?, + StaticAlloc, + ); + new_ema.alloc()?; + + unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } + } + }; + + next_ema.insert_before(new_ema_ref); + return Ok(free_addr); + } + + // Not considering concurrency and lock + // TODO: carefull examination !! + pub fn commit(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { + let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; + let start_ema_ptr = cursor.get().unwrap() as *const EMA; + + // check ema can commit + let mut count = ema_num; + while count != 0 { + cursor.get().unwrap().commit_check()?; + cursor.move_next(); + count -= 1; + } + + let mut cursor = match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, + }; + + count = ema_num; + while count != 0 { + unsafe { cursor.get_mut().unwrap().commit_self()? }; + cursor.move_next(); + count -= 1; + } + + Ok(()) + } + + pub fn dealloc(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { + let (mut cursor, mut ema_num) = self.search_ema_range(addr, addr + size, typ, false)?; + while ema_num != 0 { + unsafe { cursor.get_mut().unwrap().dealloc()? }; + cursor.move_next(); + ema_num -= 1; + } + Ok(()) + } + + pub fn modify_type( + &mut self, + addr: usize, + size: usize, + new_page_typ: PageType, + range_typ: RangeType, + ) -> SgxResult { + if new_page_typ != PageType::Tcs { + return Err(SgxStatus::InvalidParameter); + } + + if size != SE_PAGE_SIZE { + return Err(SgxStatus::InvalidParameter); + } + + let (mut cursor, mut ema_num) = + self.search_ema_range(addr, addr + size, range_typ, true)?; + assert!(ema_num == 1); + unsafe { cursor.get_mut().unwrap().change_to_tcs()? }; + + Ok(()) + } + + pub fn modify_perms( + &mut self, + addr: usize, + size: usize, + prot: ProtFlags, + typ: RangeType, + ) -> SgxResult { + ensure!( + (size != 0) + && (size % SE_PAGE_SIZE == 0) + && (addr % SE_PAGE_SIZE == 0) + && (prot.contains(ProtFlags::X) && !prot.contains(ProtFlags::R)), + SgxStatus::InvalidParameter + ); + let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; + let start_ema_ptr = cursor.get().unwrap() as *const EMA; + + // check ema can commit + let mut count = ema_num; + while count != 0 { + cursor.get().unwrap().modify_perm_check()?; + cursor.move_next(); + count -= 1; + } + + let mut cursor = match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, + }; + + count = ema_num; + while count != 0 { + unsafe { cursor.get_mut().unwrap().modify_perm(prot) }; + cursor.move_next(); + count -= 1; + } + + Ok(()) + } + + pub fn uncommit(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { + let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; + let start_ema_ptr = cursor.get().unwrap() as *const EMA; + + // check ema can commit + let mut count = ema_num; + while count != 0 { + cursor.get().unwrap().uncommit_check()?; + cursor.move_next(); + count -= 1; + } + + let mut cursor = match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, + }; + + count = ema_num; + while count != 0 { + unsafe { cursor.get_mut().unwrap().uncommit_self() }; + cursor.move_next(); + count -= 1; + } + + Ok(()) + } + + // search for a range of nodes containing addresses within [start, end) + // 'ema_begin' will hold the fist ema that has address higher than /euqal to + // 'start' 'ema_end' will hold the node immediately follow the last ema that has + // address lower than / equal to 'end' + // return ema_end and ema num + fn search_ema_range( + &mut self, + start: usize, + end: usize, + typ: RangeType, + continuous: bool, + ) -> SgxResult<(CursorMut<'_, EmaAda>, usize)> { + let mut cursor = match typ { + RangeType::Rts => self.rts.front(), + RangeType::User => self.user.front(), + }; + + while !cursor.is_null() && cursor.get().unwrap().lower_than_addr(start) { + cursor.move_next(); + } + + if cursor.is_null() || cursor.get().unwrap().higher_than_addr(end) { + return Err(SgxStatus::InvalidParameter); + } + + let mut curr_ema = cursor.get().unwrap(); + + let mut start_ema_ptr = curr_ema as *const EMA; + let mut emas_num = 0; + let mut prev_end = curr_ema.start(); + + while !cursor.is_null() && !cursor.get().unwrap().higher_than_addr(end) { + curr_ema = cursor.get().unwrap(); + // If continuity is required, there should + // be no gaps in the specified range in the emas list. + if continuous && prev_end != curr_ema.start() { + return Err(SgxStatus::InvalidParameter); + } + + emas_num += 1; + prev_end = curr_ema.end(); + cursor.move_next(); + } + + drop(cursor); + + let mut end_ema_ptr = curr_ema as *const EMA; + + // Found the overlapping emas with range [start, end) + // needs to splitting emas + + // Spliting start ema + let mut start_cursor = match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, + }; + + let curr_ema = unsafe { start_cursor.get_mut().unwrap() }; + let ema_start = curr_ema.start(); + + // Problem may exist, need to check!! + if ema_start < start { + let right_ema = curr_ema.split(start).unwrap() as *const EMA; + let right_ema_ref = unsafe { UnsafeRef::from_raw(right_ema) }; + start_cursor.insert_after(right_ema_ref); + start_cursor.move_next(); + start_ema_ptr = start_cursor.get().unwrap() as *const EMA; + } + + if emas_num == 1 { + end_ema_ptr = start_ema_ptr; + } + drop(start_cursor); + + // Spliting end ema + let mut end_cursor = match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(end_ema_ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(end_ema_ptr) }, + }; + + let end_ema = unsafe { end_cursor.get_mut().unwrap() }; + let ema_end = end_ema.end(); + + if ema_end > end { + let right_ema = end_ema.split(end).unwrap(); + let right_ema_ref = unsafe { UnsafeRef::from_raw(right_ema) }; + end_cursor.insert_after(right_ema_ref); + } + drop(end_cursor); + + // Recover start ema and return it as range + let start_cursor = match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, + }; + + return Ok((start_cursor, emas_num)); + } + + // Find a free space at addr with 'len' bytes in reserve region, + // the request space mustn't intersect with existed ema node. + // If success, return the next ema cursor. + fn find_free_region_at( + &mut self, + addr: usize, + len: usize, + typ: RangeType, + ) -> SgxResult> { + if !is_within_enclave(addr as *const u8, len) { + return Err(SgxStatus::InvalidParameter); + } + match typ { + RangeType::Rts => { + if !is_within_rts_range(addr, len) { + return Err(SgxStatus::InvalidParameter); + } + } + RangeType::User => { + if !is_within_user_range(addr, len) { + return Err(SgxStatus::InvalidParameter); + } + } + } + + let mut cursor: CursorMut<'_, EmaAda> = match typ { + RangeType::Rts => self.rts.front_mut(), + RangeType::User => self.user.front_mut(), + }; + + while !cursor.is_null() { + let start_curr = cursor.get().map(|ema| ema.start()).unwrap(); + let end_curr = start_curr + cursor.get().map(|ema| ema.len()).unwrap(); + if start_curr >= addr + len { + return Ok(cursor); + } + + if addr >= end_curr { + cursor.move_next(); + } else { + break; + } + } + + // means addr is larger than the end of the last ema node + if cursor.is_null() { + return Ok(cursor); + } + + return Err(SgxStatus::InvalidParameter); + } + + // Find a free space of size at least 'size' bytes in reserve region, + // return the start address + fn find_free_region( + &mut self, + len: usize, + align: usize, + typ: RangeType, + ) -> SgxResult<(usize, CursorMut<'_, EmaAda>)> { + let user_range = USER_RANGE.get().unwrap(); + let user_base = user_range.start; + let user_end = user_range.end; + + let mut addr = 0; + + let mut cursor: CursorMut<'_, EmaAda> = match typ { + RangeType::Rts => self.rts.front_mut(), + RangeType::User => self.user.front_mut(), + }; + + // no ema in list + if cursor.is_null() { + match typ { + RangeType::Rts => { + if user_base >= len { + addr = trim_to!(user_base - len, align); + if is_within_enclave(addr as *const u8, len) { + return Ok((addr, cursor)); + } + } else { + addr = round_to!(user_end, align); + // no integer overflow + if addr + len >= addr && is_within_enclave(addr as *const u8, len) { + return Ok((addr, cursor)); + } + } + return Err(SgxStatus::InvalidParameter); + } + RangeType::User => { + addr = round_to!(user_base, align); + if is_within_user_range(addr, len) { + return Ok((addr, cursor)); + } + return Err(SgxStatus::InvalidParameter); + } + } + } + + let mut cursor_next = cursor.peek_next(); + + // ema is_null means pointing to the Null object, not means this ema is empty + while !cursor_next.is_null() { + let curr_end = cursor.get().map(|ema| ema.aligned_end(align)).unwrap(); + + let next_start = cursor_next.get().map(|ema| ema.start()).unwrap(); + + if curr_end <= next_start { + let free_size = next_start - curr_end; + if free_size >= len { + if typ == RangeType::User || is_within_rts_range(curr_end, len) { + cursor.move_next(); + return Ok((curr_end, cursor)); + } + } + } + cursor.move_next(); + cursor_next = cursor.peek_next(); + } + + addr = cursor.get().map(|ema| ema.aligned_end(align)).unwrap(); + + if is_within_enclave(addr as *const u8, len) { + if (typ == RangeType::Rts && is_within_rts_range(addr, len)) + || (typ == RangeType::User && is_within_user_range(addr, len)) + { + cursor.move_next(); + return Ok((addr, cursor)); + } + } + + // Cursor moves to emas->front_mut. + // Firstly cursor moves to None, then moves to linkedlist head + cursor.move_next(); + cursor.move_next(); + + // Back to the first ema to check rts region before user region + let start_first = cursor.get().map(|ema| ema.start()).unwrap(); + if start_first < len { + return Err(SgxStatus::InvalidParameter); + } + + addr = trim_to!(start_first, align); + + match typ { + RangeType::User => { + if is_within_user_range(addr, len) { + return Ok((addr, cursor)); + } + } + RangeType::Rts => { + if is_within_enclave(addr as *const u8, len) && is_within_rts_range(addr, len) { + return Ok((addr, cursor)); + } + } + } + + Err(SgxStatus::InvalidParameter) + } +} diff --git a/sgx_trts/src/emm/user.rs b/sgx_trts/src/emm/user.rs index ebd2dabc9..25cf96c9e 100644 --- a/sgx_trts/src/emm/user.rs +++ b/sgx_trts/src/emm/user.rs @@ -15,18 +15,7 @@ // specific language governing permissions and limitations // under the License.. -use super::ema::{ResEmaAda, EMA}; -use crate::emm::interior::Reserve; -use crate::enclave::MmLayout; -use alloc::boxed::Box; -use alloc::sync::Arc; -use core::alloc::Layout; -use core::ffi::c_void; -use core::ptr::NonNull; -use intrusive_collections::intrusive_adapter; -use intrusive_collections::{LinkedList, LinkedListLink}; -use sgx_types::error::{SgxResult, SgxStatus}; -use spin::{Mutex, Once}; +use spin::Once; #[derive(Clone, Copy)] pub struct UserRange { @@ -83,37 +72,3 @@ pub fn is_within_user_range(start: usize, len: usize) -> bool { (start <= end) && (start >= user_start) && (end < user_end) } - -pub struct UserMem { - emas: LinkedList, - - // statistics - allocated: usize, - total: usize, -} - -impl UserMem { - pub fn new() -> Self { - Self { - emas: LinkedList::new(ResEmaAda::new()), - allocated: 0, - total: 0, - } - } - // fn split(ema: Box) -> SgxResult<()>{ - // todo!() - // } - // fn merge(ema1: Box, ema2: Box) - // -> SgxResult<()> { - // todo!() - // } - pub fn alloc(&mut self, layout: Layout) -> Result, ()> { - todo!() - } - pub fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - todo!() - } - pub fn commit(&mut self, layout: Layout) -> Result, ()> { - todo!() - } -} diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs index 9c8d687c9..69cb8283d 100644 --- a/sgx_trts/src/lib.rs +++ b/sgx_trts/src/lib.rs @@ -37,6 +37,7 @@ #![allow(dead_code)] #![allow(non_camel_case_types)] #![feature(linked_list_cursors)] +#![feature(strict_provenance)] #[cfg(all(feature = "sim", feature = "hyper"))] compile_error!("feature \"sim\" and feature \"hyper\" cannot be enabled at the same time"); From cce355922fafeccd0504514f13b0945e140f02e1 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Tue, 8 Aug 2023 18:59:51 +0800 Subject: [PATCH 04/20] Implement page fault handler --- sgx_trts/Cargo.toml | 1 + sgx_trts/src/arch.rs | 1 + sgx_trts/src/emm/alloc.rs | 7 +- sgx_trts/src/emm/bitmap.rs | 58 +++---- sgx_trts/src/emm/ema.rs | 209 +++++++++++++--------- sgx_trts/src/emm/interior.rs | 315 +++++++++++++++++++--------------- sgx_trts/src/emm/mod.rs | 9 + sgx_trts/src/emm/pfhandler.rs | 115 +++++++++++++ sgx_trts/src/emm/range.rs | 115 ++++++++----- sgx_trts/src/emm/user.rs | 4 +- sgx_trts/src/lib.rs | 1 + 11 files changed, 534 insertions(+), 301 deletions(-) create mode 100644 sgx_trts/src/emm/pfhandler.rs diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml index ebed5c748..9c49f4aff 100644 --- a/sgx_trts/Cargo.toml +++ b/sgx_trts/Cargo.toml @@ -34,6 +34,7 @@ default = [] thread = [] sim = ["sgx_types/sim"] hyper = ["sgx_types/hyper"] +emm_test = [] [dependencies] sgx_types = { path = "../sgx_types" } diff --git a/sgx_trts/src/arch.rs b/sgx_trts/src/arch.rs index 0350fa256..d98c03118 100644 --- a/sgx_trts/src/arch.rs +++ b/sgx_trts/src/arch.rs @@ -40,6 +40,7 @@ macro_rules! is_page_aligned { }; } +// rounds to up macro_rules! round_to { ($num:expr, $align:expr) => { ($num + $align - 1) & (!($align - 1)) diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index 9adad6f1c..dde3b5c85 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -3,7 +3,7 @@ use core::ptr::NonNull; use crate::emm::interior::{RES_ALLOCATOR, STATIC}; -/// alloc layout memory from Reserve region +/// Alloc layout memory from reserve memory region #[derive(Clone, Copy)] pub struct ResAlloc; @@ -25,12 +25,15 @@ unsafe impl Allocator for ResAlloc { } } +/// Alloc layout memory from static memory region #[derive(Clone, Copy)] pub struct StaticAlloc; unsafe impl Allocator for StaticAlloc { fn allocate(&self, layout: Layout) -> Result, AllocError> { STATIC + .get() + .unwrap() .lock() .alloc(layout) .map(|addr| NonNull::slice_from_raw_parts(addr, layout.size())) @@ -39,6 +42,6 @@ unsafe impl Allocator for StaticAlloc { #[inline] unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - STATIC.lock().dealloc(ptr, layout); + STATIC.get().unwrap().lock().dealloc(ptr, layout); } } diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index d78b2f527..479747a39 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -28,7 +28,7 @@ use super::alloc::StaticAlloc; use super::interior::Alloc; #[repr(C)] -#[derive(Clone)] +#[derive(Debug)] pub struct BitArray { bits: usize, bytes: usize, @@ -37,13 +37,14 @@ pub struct BitArray { } impl BitArray { - /// Init BitArray in Reserve memory with all zeros. + /// Init BitArray with all zero bits pub fn new(bits: usize, alloc: Alloc) -> SgxResult { let bytes = (bits + 7) / 8; - // FIXME: return error if out of memory + // FIXME: return error if OOM let data = match alloc { Alloc::Reserve => { + // Set bits to all zeros let data = vec::from_elem_in(0_u8, bytes, ResAlloc).into_boxed_slice(); Box::into_raw(data) as *mut u8 } @@ -61,28 +62,34 @@ impl BitArray { }) } - // Get the value of the bit at a given index. - // todo: return SgxResult - pub fn get(&self, index: usize) -> bool { + /// Get the value of the bit at a given index + pub fn get(&self, index: usize) -> SgxResult { + if index >= self.bits { + return Err(SgxStatus::InvalidParameter); + } + let byte_index = index / 8; let bit_index = index % 8; let bit_mask = 1 << bit_index; let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; - (data.get(byte_index).unwrap() & bit_mask) != 0 + Ok((data.get(byte_index).unwrap() & bit_mask) != 0) } - // check whether each bit set true + /// Check whether all bits are set true pub fn all_true(&self) -> bool { for pos in 0..self.bits { - if !self.get(pos) { + if !self.get(pos).unwrap() { return false; } } true } - // Set the value of the bit at a given index. - pub fn set(&mut self, index: usize, value: bool) { + /// Set the value of the bit at the specified index + pub fn set(&mut self, index: usize, value: bool) -> SgxResult { + if index >= self.bits { + return Err(SgxStatus::InvalidParameter); + } let byte_index = index / 8; let bit_index = index % 8; let bit_mask = 1 << bit_index; @@ -94,16 +101,10 @@ impl BitArray { } else { data[byte_index] &= !bit_mask; } + Ok(()) } - /// Set the value of the bit at a given index. - /// The range includes [0, index). - pub fn set_until(&mut self, index: usize, value: bool) { - todo!() - } - - /// Set the value of the bit at a given index. - /// The range includes [0, index). + /// Set all the bits to true pub fn set_full(&mut self) { let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; data.fill(0xFF); @@ -115,16 +116,15 @@ impl BitArray { data.fill(0); } - // split current bit array into left and right bit array - // return right bit array - // TODO: more check + /// Split current bit array at specified position, return a new allocated bit array + /// corresponding to the bits at the range of [pos, end). + /// And the current bit array manages the bits at the range of [0, pos). pub fn split(&mut self, pos: usize) -> SgxResult { ensure!(pos > 0 && pos < self.bits, SgxStatus::InvalidParameter); let byte_index = pos / 8; let bit_index = pos % 8; - // let l_bits = (byte_index << 3) + bit_index; let l_bits = pos; let l_bytes = (l_bits + 7) / 8; @@ -134,7 +134,6 @@ impl BitArray { let r_array = Self::new(r_bits, self.alloc.clone())?; let r_data = unsafe { core::slice::from_raw_parts_mut(r_array.data, r_array.bytes) }; - let l_data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; for (idx, item) in r_data[..(r_bytes - 1)].iter_mut().enumerate() { @@ -149,7 +148,7 @@ impl BitArray { self.bits = l_bits; self.bytes = l_bytes; - return Ok(r_array); + Ok(r_array) } } @@ -157,7 +156,9 @@ impl Drop for BitArray { fn drop(&mut self) { match self.alloc { Alloc::Reserve => { - // for interior allocator, layout is redundant + // Layout is redundant since interior allocator maintains the allocated size. + // Besides, if the bitmap is splitted, the recorded size + // in bitmap is not corresponding to allocated layout. let fake_layout: Layout = Layout::new::(); unsafe { let data_ptr = NonNull::new_unchecked(self.data); @@ -165,9 +166,6 @@ impl Drop for BitArray { } } Alloc::Static => { - // for interior allocator, layout is redundant - // If the bitmap is splitted, the size of - // allocated layout is not recorded in bitmap struct let fake_layout: Layout = Layout::new::(); unsafe { let data_ptr = NonNull::new_unchecked(self.data); @@ -177,5 +175,3 @@ impl Drop for BitArray { } } } - -// FIXME: add more unit test diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index db540e9dd..62bb45b06 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -21,7 +21,6 @@ use crate::edmm::perm; use crate::edmm::PageRange; use crate::edmm::{PageInfo, PageType, ProtFlags}; use crate::enclave::is_within_enclave; -use alloc::alloc::Global; use alloc::boxed::Box; use intrusive_collections::intrusive_adapter; use intrusive_collections::LinkedListLink; @@ -31,29 +30,31 @@ use sgx_types::error::SgxStatus; use crate::feature::SysFeatures; use crate::trts::Version; -use crate::veh::{ExceptionHandler, ExceptionInfo}; use super::alloc::ResAlloc; use super::alloc::StaticAlloc; use super::bitmap::BitArray; use super::flags::AllocFlags; use super::interior::Alloc; +use super::pfhandler::PfHandler; +use super::pfhandler::PfInfo; +/// Enclave Management Area #[repr(C)] -#[derive(Clone)] pub struct EMA { - // starting address, page aligned + // page aligned start address start: usize, - // bytes, or page may be more available + // bytes, round to page bytes length: usize, alloc_flags: AllocFlags, info: PageInfo, // bitmap for EACCEPT status + // FIXME: replace BitArray with pointer eaccept_map: Option, // custom PF handler - handler: Option, - // private data for handler - priv_data: Option<*mut ExceptionInfo>, + handler: Option, + // private data for PF handler + priv_data: Option<*mut PfInfo>, alloc: Alloc, // intrusive linkedlist link: LinkedListLink, @@ -64,17 +65,18 @@ unsafe impl Send for EMA {} unsafe impl Sync for EMA {} impl EMA { - // start address must be page aligned + /// Initialize EMA node with null eaccept map, + /// and start address must be page aligned pub fn new( start: usize, length: usize, alloc_flags: AllocFlags, info: PageInfo, - handler: Option, - priv_data: Option<*mut ExceptionInfo>, + handler: Option, + priv_data: Option<*mut PfInfo>, alloc: Alloc, ) -> SgxResult { - // check flags' eligibility + // check alloc flags' eligibility AllocFlags::try_from(alloc_flags.bits())?; if start != 0 @@ -83,7 +85,7 @@ impl EMA { && is_page_aligned!(start) && (length % crate::arch::SE_PAGE_SIZE) == 0 { - return Ok(Self { + Ok(Self { start, length, alloc_flags, @@ -93,15 +95,15 @@ impl EMA { priv_data, link: LinkedListLink::new(), alloc, - }); + }) } else { - return Err(SgxStatus::InvalidParameter); + Err(SgxStatus::InvalidParameter) } } - // Returns a newly allocated ema in charging of the memory in the range [addr, addr + len). - // After the call, the original ema will be left containing the elements [start, addr) - // with its previous capacity unchanged. + /// Split current ema at specified address, return a new allocated ema + /// corresponding to the memory at the range of [addr, end). + /// And the current ema manages the memory at the range of [start, addr). pub fn split(&mut self, addr: usize) -> SgxResult<*mut EMA> { let l_start = self.start; let l_length = addr - l_start; @@ -112,22 +114,46 @@ impl EMA { let new_bitarray = match &mut self.eaccept_map { Some(bitarray) => { let pos = (addr - self.start) >> crate::arch::SE_PAGE_SHIFT; - // split self.eaccept_map Some(bitarray.split(pos)?) } None => None, }; + // Initialize EMA with same allocator let new_ema: *mut EMA = match self.alloc { Alloc::Reserve => { - let mut ema = Box::new_in(self.clone(), ResAlloc); + let mut ema = Box::new_in( + EMA::new( + self.start, + self.length, + self.alloc_flags, + self.info, + self.handler, + self.priv_data, + Alloc::Reserve, + ) + .unwrap(), + ResAlloc, + ); ema.start = r_start; ema.length = r_length; ema.eaccept_map = new_bitarray; Box::into_raw(ema) } Alloc::Static => { - let mut ema = Box::new_in(self.clone(), StaticAlloc); + let mut ema = Box::new_in( + EMA::new( + self.start, + self.length, + self.alloc_flags, + self.info, + self.handler, + self.priv_data, + Alloc::Static, + ) + .unwrap(), + StaticAlloc, + ); ema.start = r_start; ema.length = r_length; ema.eaccept_map = new_bitarray; @@ -138,56 +164,46 @@ impl EMA { self.start = l_start; self.length = l_length; - return Ok(new_ema); + Ok(new_ema) } - // FIXME: handling reserve ema node doesn't have ema eaccept - /// Alloc the reserve / committed / vitual memory indeed + /// Allocate the reserve / committed / virtual memory at corresponding memory pub fn alloc(&mut self) -> SgxResult { + // RESERVED region only occupy memory range, but no real allocation if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); } - // new self bitmap + // Allocate new eaccept_map for COMMIT_ON_DEMAND and COMMIT_NOW + if self.eaccept_map.is_none() { + let eaccept_map = match self.alloc { + Alloc::Reserve => { + let page_num = self.length >> SE_PAGE_SHIFT; + BitArray::new(page_num, Alloc::Reserve)? + } + Alloc::Static => { + let page_num = self.length >> SE_PAGE_SHIFT; + BitArray::new(page_num, Alloc::Static)? + } + }; + self.eaccept_map = Some(eaccept_map); + }; - // COMMIT_ON_DEMAND and COMMIT_NOW both need to mmap memory in urts + // Ocall to mmap memory in urts perm::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags)?; + // Set the corresponding bits of eaccept map if self.alloc_flags.contains(AllocFlags::COMMIT_NOW) { - let grow_up: bool = if self.alloc_flags.contains(AllocFlags::GROWSDOWN) { - false - } else { - true - }; + let grow_up: bool = !self.alloc_flags.contains(AllocFlags::GROWSDOWN); self.eaccept(self.start, self.length, grow_up)?; - // set eaccept map full - match &mut self.eaccept_map { - Some(map) => { - map.set_full(); - } - None => { - // COMMIT_NOW must have eaccept_map - return Err(SgxStatus::Unexpected); - } - } + self.eaccept_map.as_mut().unwrap().set_full(); } else { - // clear eaccept map - match &mut self.eaccept_map { - Some(map) => { - map.clear(); - } - None => { - // COMMIT_NOW must have eaccept_map - return Err(SgxStatus::Unexpected); - } - } + self.eaccept_map.as_mut().unwrap().clear(); } - return Ok(()); + Ok(()) } - /// do eaccept for targeted EPC page - /// similiar to "apply_epc_pages(addr: usize, count: usize)" / intel emm do_commit() - /// do not change eaccept map + /// Eaccept target EPC pages with cpu instruction fn eaccept(&self, start: usize, length: usize, grow_up: bool) -> SgxResult { let info = PageInfo { typ: self.info.typ, @@ -203,7 +219,7 @@ impl EMA { } } - // Attension, return EACCES SgxStatus may be more appropriate + /// Check the prerequisites of ema commitment pub fn commit_check(&self) -> SgxResult { if self.info.prot.intersects(ProtFlags::R | ProtFlags::W) { return Err(SgxStatus::InvalidParameter); @@ -220,12 +236,12 @@ impl EMA { Ok(()) } - /// commit all the memory in this ema + /// Commit the corresponding memory of this ema pub fn commit_self(&mut self) -> SgxResult { self.commit(self.start, self.length) } - /// ema_do_commit + /// Commit the partial memory of this ema pub fn commit(&mut self, start: usize, length: usize) -> SgxResult { ensure!( length != 0 @@ -242,22 +258,23 @@ impl EMA { let pages = PageRange::new(start, length / crate::arch::SE_PAGE_SIZE, info)?; - // page index for parsing start address + // Page index of the start address let init_idx = (start - self.start) >> crate::arch::SE_PAGE_SHIFT; let map = self.eaccept_map.as_mut().unwrap(); for (idx, page) in pages.iter().enumerate() { let page_idx = idx + init_idx; - if map.get(page_idx) { + if map.get(page_idx).unwrap() { continue; } else { page.accept()?; - map.set(page_idx, true); + map.set(page_idx, true)?; } } - return Ok(()); + Ok(()) } + /// Check the prerequisites of ema uncommitment pub fn uncommit_check(&self) -> SgxResult { if self.alloc_flags.contains(AllocFlags::RESERVED) { return Err(SgxStatus::InvalidParameter); @@ -265,6 +282,7 @@ impl EMA { Ok(()) } + /// Uncommit the corresponding memory of this ema pub fn uncommit_self(&mut self) -> SgxResult { let prot = self.info.prot; if prot == ProtFlags::NONE { @@ -274,9 +292,8 @@ impl EMA { self.uncommit(self.start, self.length, prot) } - /// uncommit EPC page + /// Uncommit the partial memory of this ema pub fn uncommit(&mut self, start: usize, length: usize, prot: ProtFlags) -> SgxResult { - // need READ for trimming ensure!(self.eaccept_map.is_some(), SgxStatus::InvalidParameter); if self.alloc_flags.contains(AllocFlags::RESERVED) { @@ -292,12 +309,11 @@ impl EMA { let mut start = start; let end: usize = start + length; - // TODO: optimized with [u8] slice while start < end { let mut block_start = start; while block_start < end { let pos = (block_start - self.start) >> crate::arch::SE_PAGE_SHIFT; - if map.get(pos) { + if map.get(pos).unwrap() { break; } else { block_start += crate::arch::SE_PAGE_SIZE; @@ -311,7 +327,7 @@ impl EMA { let mut block_end = block_start + crate::arch::SE_PAGE_SIZE; while block_end < end { let pos = (block_end - self.start) >> crate::arch::SE_PAGE_SHIFT; - if map.get(pos) { + if map.get(pos).unwrap() { block_end += crate::arch::SE_PAGE_SIZE; } else { break; @@ -342,10 +358,10 @@ impl EMA { for (idx, page) in pages.iter().enumerate() { page.accept()?; let pos = idx + init_idx; - map.set(pos, false); + map.set(pos, false)?; } - // eaccept trim notify + // Notify trimming perm::modify_ocall( block_start, block_length, @@ -363,6 +379,7 @@ impl EMA { Ok(()) } + /// Check the prerequisites of modifying permissions pub fn modify_perm_check(&self) -> SgxResult { if self.info.typ != PageType::Reg { return Err(SgxStatus::InvalidParameter); @@ -386,11 +403,13 @@ impl EMA { Ok(()) } + /// Modifying the permissions of corresponding memory of this ema pub fn modify_perm(&mut self, new_prot: ProtFlags) -> SgxResult { if self.info.prot == new_prot { return Ok(()); } + // Notify modifying permissions if SysFeatures::get().version() == Version::Sdk2_0 { perm::modify_ocall( self.start, @@ -410,17 +429,16 @@ impl EMA { let pages = PageRange::new(self.start, self.length / crate::arch::SE_PAGE_SIZE, info)?; + // Modpe the EPC with cpu instruction for page in pages.iter() { - // If new_prot is the subset of self.info.prot, no need to apply modpe. - // So we can't use new_prot != self.info.prot as determination if (new_prot | self.info.prot) != self.info.prot { page.modpe()?; } - // new permission is RWX, no EMODPR needed in untrusted part, hence no - // EACCEPT + // If the new permission is RWX, no EMODPR needed in untrusted part (modify ocall) if (new_prot & (ProtFlags::W | ProtFlags::X)) != (ProtFlags::W | ProtFlags::X) { page.accept()?; + return Ok(()); } } @@ -447,20 +465,19 @@ impl EMA { Ok(()) } + /// Changing the page type from Reg to Tcs pub fn change_to_tcs(&mut self) -> SgxResult { - // the ema has and only has one page + // The ema must have and only have one page if self.length != SE_PAGE_SIZE { return Err(SgxStatus::InvalidParameter); } - // page must be committed + // The page must be committed if !self.is_page_committed(self.start) { return Err(SgxStatus::InvalidParameter); } let info = self.info; - - // page has been changed to tcs if info.typ == PageType::Tcs { return Ok(()); } @@ -501,15 +518,16 @@ impl EMA { Ok(()) } - fn is_page_committed(&self, addr: usize) -> bool { + pub fn is_page_committed(&self, addr: usize) -> bool { assert!(addr % SE_PAGE_SIZE == 0); if self.eaccept_map.is_none() { return false; } let pos = (addr - self.start) >> SE_PAGE_SHIFT; - self.eaccept_map.as_ref().unwrap().get(pos) + self.eaccept_map.as_ref().unwrap().get(pos).unwrap() } + /// Deallocate the corresponding memory of this ema pub fn dealloc(&mut self) -> SgxResult { if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); @@ -522,46 +540,67 @@ impl EMA { Ok(()) } + /// Obtain the aligned end address pub fn aligned_end(&self, align: usize) -> usize { let curr_end = self.start + self.length; round_to!(curr_end, align) } + /// Obtain the end address of ema pub fn end(&self) -> usize { self.start + self.length } + /// Obtain the start address of ema pub fn start(&self) -> usize { self.start } + /// Obtain the length of ema (bytes) pub fn len(&self) -> usize { self.length } + /// Check if the ema range is lower than the address pub fn lower_than_addr(&self, addr: usize) -> bool { self.end() <= addr } + /// Check if the ema range is higher than the address pub fn higher_than_addr(&self, addr: usize) -> bool { self.start >= addr } - pub fn set_flags(&mut self, flags: AllocFlags) { + /// Check if the ema range contains the specified address + pub fn overlap_addr(&self, addr: usize) -> bool { + (addr >= self.start) && (addr < self.start + self.length) + } + + fn set_flags(&mut self, flags: AllocFlags) { self.alloc_flags = flags; } - pub fn set_prot(&mut self, info: PageInfo) { + + fn set_prot(&mut self, info: PageInfo) { self.info = info; } - fn flags(&self) -> AllocFlags { + + /// Obtain the allocator of ema + pub fn allocator(&self) -> Alloc { + self.alloc.clone() + } + + pub fn flags(&self) -> AllocFlags { self.alloc_flags } - fn info(&self) -> PageInfo { + + pub fn info(&self) -> PageInfo { self.info } - fn handler(&self) -> Option { - self.handler + + pub fn fault_handler(&self) -> (Option, Option<*mut PfInfo>) { + (self.handler, self.priv_data) } } +// Implement ema adapter for the operations of intrusive linkedlist intrusive_adapter!(pub EmaAda = UnsafeRef: EMA { link: LinkedListLink }); diff --git a/sgx_trts/src/emm/interior.rs b/sgx_trts/src/emm/interior.rs index 4835a426c..d0c111e8f 100644 --- a/sgx_trts/src/emm/interior.rs +++ b/sgx_trts/src/emm/interior.rs @@ -20,9 +20,7 @@ use intrusive_collections::intrusive_adapter; use intrusive_collections::singly_linked_list::CursorMut; use intrusive_collections::singly_linked_list::{Link, SinglyLinkedList}; use intrusive_collections::UnsafeRef; -use intrusive_collections::{LinkedList, LinkedListLink}; -use crate::sync::SpinMutex; use core::mem::size_of; use core::mem::transmute; use core::mem::MaybeUninit; @@ -32,59 +30,66 @@ use super::flags::AllocFlags; use super::range::{RangeType, RM}; use sgx_types::error::{SgxResult, SgxStatus}; -// fixed static memory size +// The size of fixed static memory for Static Allocator const STATIC_MEM_SIZE: usize = 65536; -// initial interior reserve memory size + +// The size of initial reserve memory for Reserve Allocator const INIT_MEM_SIZE: usize = 65536; -// the size of guard for interior memory + +// The size of guard pages const GUARD_SIZE: usize = 0x8000; -// this is enough for bit map of an 8T EMA + +// The max allocated size of Reserve Allocator const MAX_EMALLOC_SIZE: usize = 0x10000000; const ALLOC_MASK: usize = 1; const SIZE_MASK: usize = !(EXACT_MATCH_INCREMENT - 1); -// the increment size for interior memory -static mut INCR_SIZE: usize = 65536; - -/// first level: static memory -pub static STATIC: LockedHeap<32> = LockedHeap::empty(); - -#[derive(Clone)] -#[repr(u8)] -pub enum Alloc { - Static, - Reserve, +/// Init two level allocator +pub fn init_alloc() { + init_static_alloc(); + init_reserve_alloc() } +/// Lowest level: Allocator for static memory +pub static STATIC: Once> = Once::new(); + +/// Static memory for allocation static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; -pub fn init_static_alloc() { - unsafe { - STATIC - .lock() - .init(STATIC_MEM.as_ptr() as usize, STATIC_MEM_SIZE); - } +/// Init lowest level static memory allocator +fn init_static_alloc() { + STATIC.call_once(|| { + let static_alloc = LockedHeap::empty(); + unsafe { + static_alloc + .lock() + .init(STATIC_MEM.as_ptr() as usize, STATIC_MEM_SIZE) + }; + static_alloc + }); } -/// second level: reserve memory -/// Some problem here! -// static RES_ALLOCATOR: Once> = Once::new(); +/// Second level: Allocator for reserve memory pub static RES_ALLOCATOR: Once> = Once::new(); -pub static GLOBAL_LOCK: Once> = Once::new(); -pub fn init_global_lock() { - GLOBAL_LOCK.call_once(|| SpinMutex::new(())); +/// Init reserve memory allocator +/// init_reserve_alloc() need to be called after init_static_alloc() +fn init_reserve_alloc() { + RES_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); } -pub fn init_reserve_alloc() -> SgxResult { - let reserve = Mutex::new(Reserve::new(1024)?); - // res_allocator need to be intialized after static_allocator - RES_ALLOCATOR.call_once(|| reserve); - Ok(()) +// Enum for allocator types +#[derive(Clone, Debug)] +#[repr(u8)] +pub enum Alloc { + Static, + Reserve, } -// mm_reserve +// Chunk manages memory range. +// The Chunk structure is filled into the layout before the base pointer. +#[derive(Debug)] struct Chunk { base: usize, size: usize, @@ -103,7 +108,7 @@ impl Chunk { } } -intrusive_adapter!(ChunkAda = UnsafeRef: Chunk { link: LinkedListLink }); +intrusive_adapter!(ChunkAda = UnsafeRef: Chunk { link: Link }); const NUM_EXACT_LIST: usize = 0x100; const HEADER_SIZE: usize = size_of::(); @@ -111,20 +116,17 @@ const EXACT_MATCH_INCREMENT: usize = 0x8; const MIN_BLOCK_SIZE: usize = 0x10; const MAX_EXACT_SIZE: usize = MIN_BLOCK_SIZE + EXACT_MATCH_INCREMENT * (NUM_EXACT_LIST - 1); -enum Block { - Free(BlockFree), - Used(BlockUsed), -} - -// free block for allocationg exact size +// Free block for allocating memory with exact size #[repr(C)] +#[derive(Debug)] struct BlockFree { size: usize, - link: LinkedListLink, // doubly intrusive linkedlist + link: Link, // singly intrusive linkedlist } -// used block for tracking allocated size and base address +// Used block for tracking allocated size and base pointer #[repr(C)] +#[derive(Debug)] struct BlockUsed { size: usize, payload: usize, @@ -134,10 +136,14 @@ impl BlockFree { fn new(size: usize) -> Self { Self { size, - link: LinkedListLink::new(), + link: Link::new(), } } + fn set_size(&mut self, size: usize) { + self.size = size; + } + fn block_size(&self) -> usize { self.size & SIZE_MASK } @@ -147,80 +153,115 @@ impl BlockUsed { fn new(size: usize) -> Self { Self { size, payload: 0 } } + + fn set_size(&mut self, size: usize) { + self.size = size; + } + + fn block_size(&self) -> usize { + self.size & SIZE_MASK + } + + fn is_alloced(&self) -> bool { + self.size & ALLOC_MASK == 0 + } + + fn set_alloced(&mut self) { + self.size |= ALLOC_MASK; + } + + fn clear_alloced(&mut self) { + self.size &= SIZE_MASK; + } } -intrusive_adapter!(BlockFreeAda = UnsafeRef: BlockFree { link: LinkedListLink }); +intrusive_adapter!(BlockFreeAda = UnsafeRef: BlockFree { link: Link }); +/// Interior allocator for reserve memory management, pub struct Reserve { - // Each block manage an area of free memory - exact_blocks: [LinkedList; 256], - large_blocks: LinkedList, - - // Each chunk manage an area of memory allocated by one EMA + exact_blocks: [SinglyLinkedList; 256], + large_blocks: SinglyLinkedList, chunks: SinglyLinkedList, - + // The size of memory increment + incr_size: usize, // statistics allocated: usize, total: usize, } impl Reserve { - pub fn new(size: usize) -> SgxResult { - let exact_blocks: [LinkedList; 256] = { - let mut exact_blocks: [MaybeUninit>; 256] = + fn new(size: usize) -> Self { + let exact_blocks: [SinglyLinkedList; 256] = { + let mut exact_blocks: [MaybeUninit>; 256] = MaybeUninit::uninit_array(); for block in &mut exact_blocks { - block.write(LinkedList::new(BlockFreeAda::new())); + block.write(SinglyLinkedList::new(BlockFreeAda::new())); } unsafe { transmute(exact_blocks) } }; let mut reserve = Self { exact_blocks, - large_blocks: LinkedList::new(BlockFreeAda::new()), + large_blocks: SinglyLinkedList::new(BlockFreeAda::new()), chunks: SinglyLinkedList::new(ChunkAda::new()), + incr_size: 65536, allocated: 0, total: 0, }; + + // We shouldn't handle the allocation error of reserve memory when initializing, + // If it returns error, the sdk should panic and crash. unsafe { - reserve.add_reserve(size)?; + reserve.add_chunks(size).unwrap(); } - Ok(reserve) + reserve } + // Find the available free block for memory allocation, + // and bsize must be round to eight fn get_free_block(&mut self, bsize: usize) -> Option> { if bsize <= MAX_EXACT_SIZE { + // TODO: for exact size block, maybe we can reuse larger block + // rather than allocating block from chunk return self.get_exact_block(bsize); } - // loop and find the most available large block + // Loop and find the most available large block let list = &mut self.large_blocks; let mut cursor = list.front_mut(); let mut suit_block: Option<*const BlockFree> = None; let mut suit_block_size = 0; while !cursor.is_null() { let curr_block = cursor.get().unwrap(); - if curr_block.size >= bsize { - if suit_block.is_none() { - suit_block = Some(curr_block as *const BlockFree); - suit_block_size = curr_block.size; - } else if suit_block_size > curr_block.size { - suit_block = Some(curr_block as *const BlockFree); - suit_block_size = curr_block.size; - } + if curr_block.size >= bsize + && (suit_block.is_none() || (suit_block_size > curr_block.size)) + { + suit_block = Some(curr_block as *const BlockFree); + suit_block_size = curr_block.block_size(); } cursor.move_next(); } - if suit_block.is_none() { - return None; + suit_block?; + + cursor = list.front_mut(); + + let mut curr_block_ptr = cursor.get().unwrap() as *const BlockFree; + if curr_block_ptr == suit_block.unwrap() { + return list.pop_front(); } - let mut cursor = unsafe { list.cursor_mut_from_ptr(suit_block.unwrap()) }; - let suit_block = cursor.remove(); + let mut cursor_next = cursor.peek_next(); + while !cursor_next.is_null() { + curr_block_ptr = cursor_next.get().unwrap() as *const BlockFree; + if curr_block_ptr == suit_block.unwrap() { + return cursor.remove_next(); + } + cursor.move_next(); + cursor_next = cursor.peek_next(); + } - // TODO: split suit block - return suit_block; + None } fn get_exact_block(&mut self, bsize: usize) -> Option> { @@ -232,23 +273,18 @@ impl Reserve { fn put_free_block(&mut self, block: UnsafeRef) { let block_size = block.block_size(); if block_size <= MAX_EXACT_SIZE { - // put block into list with exact block size + // put block into exact block list let idx = self.get_list_idx(block_size); let list = &mut self.exact_blocks[idx]; - list.push_back(block); + list.push_front(block); } else { - // put block into list with large block size + // put block into large block list let list = &mut self.large_blocks; - list.push_back(block); + list.push_front(block); } } - // merge next free block into this block - fn reconfigure_block(&self, _block: UnsafeRef) -> UnsafeRef { - todo!() - } - - /// Obtain the list index for exact block size + // Obtain the list index with exact block size fn get_list_idx(&self, size: usize) -> usize { assert!(size % EXACT_MATCH_INCREMENT == 0); if size < MIN_BLOCK_SIZE { @@ -256,77 +292,76 @@ impl Reserve { } let idx = (size - MIN_BLOCK_SIZE) / EXACT_MATCH_INCREMENT; assert!(idx < NUM_EXACT_LIST); - return idx; + idx } - // Attention! If we need to clear the memory + // Reconstruct BlockUsed with BlockFree block_size() and set alloc, return payload addr. + // BlockFree -> BlockUsed -> Payload addr (Used) fn block_to_payload(&self, block: UnsafeRef) -> usize { - let block_size = block.size; - let block_used = BlockUsed::new(block_size); - let ptr = UnsafeRef::into_raw(block) as *mut BlockUsed; - let payload_addr = unsafe { - ptr.write(block_used); - ptr.offset(HEADER_SIZE as isize) as usize - }; - return payload_addr; + let block_size = block.block_size(); + let mut block_used = BlockUsed::new(block_size); + block_used.set_alloced(); + + let block_used_ptr = UnsafeRef::into_raw(block) as *mut BlockUsed; + unsafe { + block_used_ptr.write(block_used); + // Regular offset shifts count*T bytes + block_used_ptr.byte_offset(HEADER_SIZE as isize) as usize + } } + // Reconstruct a new BlockFree with BlockUsed block_size(), return payload addr. + // Payload addr (Used) -> BlockUsed -> BlockFree fn payload_to_block(&self, payload_addr: usize) -> UnsafeRef { - // payload shift to block_use let payload_ptr = payload_addr as *const u8; let block_used_ptr = - unsafe { payload_ptr.offset(-(HEADER_SIZE as isize)) as *mut BlockUsed }; - - let block_size = unsafe { block_used_ptr.read().size }; + unsafe { payload_ptr.byte_offset(-(HEADER_SIZE as isize)) as *mut BlockUsed }; + // Implicitly clear alloc mask, reconstruct new BlockFree + let block_size = unsafe { block_used_ptr.read().block_size() }; let block_free = BlockFree::new(block_size); - let ptr = block_used_ptr as *mut BlockFree; + let block_free_ptr = block_used_ptr as *mut BlockFree; unsafe { - ptr.write(block_free); - UnsafeRef::from_raw(ptr) + block_free_ptr.write(block_free); + UnsafeRef::from_raw(block_free_ptr) } } + /// Malloc memory pub fn emalloc(&mut self, size: usize) -> SgxResult { let mut bsize = round_to!(size + HEADER_SIZE, EXACT_MATCH_INCREMENT); bsize = bsize.max(MIN_BLOCK_SIZE); - // find free block in lists + // Find free block in lists let mut block = self.get_free_block(bsize); - match block { - Some(mut block) => { - let block_size = bsize | ALLOC_MASK; - block.size = block_size; - return Ok(self.block_to_payload(block)); - } - None => (), + if let Some(block) = block { + // No need to set size as free block contains size + return Ok(self.block_to_payload(block)); }; - block = self.alloc_from_reserve(bsize); + // Alloc new block from chunks + block = self.alloc_from_chunks(bsize); if block.is_none() { let chunk_size = size_of::(); let new_reserve_size = round_to!(bsize + chunk_size, INIT_MEM_SIZE); - unsafe { self.add_reserve(new_reserve_size)? }; - block = self.alloc_from_reserve(bsize); - // should never happen + unsafe { self.add_chunks(new_reserve_size)? }; + block = self.alloc_from_chunks(bsize); + // Should never happen if block.is_none() { return Err(SgxStatus::InvalidParameter); } } - let mut block = block.unwrap(); - - block.size = bsize | ALLOC_MASK; - return Ok(self.block_to_payload(block)); + Ok(self.block_to_payload(block.unwrap())) } - fn alloc_from_reserve(&mut self, bsize: usize) -> Option> { + fn alloc_from_chunks(&mut self, bsize: usize) -> Option> { let mut addr: usize = 0; let mut cursor = self.chunks.front_mut(); while !cursor.is_null() { let chunk = unsafe { cursor.get_mut().unwrap() }; - if chunk.size - chunk.used >= bsize { + if (chunk.size - chunk.used) >= bsize { addr = chunk.base + chunk.used; chunk.used += bsize; break; @@ -335,7 +370,7 @@ impl Reserve { } if addr == 0 { - return None; + None } else { let block = BlockFree::new(bsize); let ptr = addr as *mut BlockFree; @@ -343,10 +378,11 @@ impl Reserve { ptr.write(block); UnsafeRef::from_raw(ptr) }; - return Some(block); + Some(block) } } + /// Free memory pub fn efree(&mut self, payload_addr: usize) { let block = self.payload_to_block(payload_addr); let block_addr = block.as_ref() as *const BlockFree as usize; @@ -356,25 +392,29 @@ impl Reserve { if res.is_err() { panic!(); } - // reconfigure block + + // TODO: reconfigure the free block, + // merging its dextral block into a large block let mut cursor = res.unwrap(); let chunk = unsafe { cursor.get_mut().unwrap() }; if block_end - chunk.base == chunk.used { - chunk.used -= block.size; + chunk.used -= block.block_size(); + // TODO: Trigger merging the right-most block into this chunk, + // if and only if the right-most block is in free large block list + return; } - // TODO: merge large block into reserve - self.put_free_block(block); } /// Adding the size of interior memory /// rsize: memory increment - pub unsafe fn add_reserve(&mut self, rsize: usize) -> SgxResult { + pub unsafe fn add_chunks(&mut self, rsize: usize) -> SgxResult { // Here we alloc at least INIT_MEM_SIZE size, // but commit rsize memory, the remaining memory is COMMIT_ON_DEMAND - let increment = INCR_SIZE.max(rsize); + let increment = self.incr_size.max(rsize); + let mut range_manage = RM.get().unwrap().lock(); let base = range_manage.alloc( None, @@ -403,16 +443,19 @@ impl Reserve { self.write_chunk(base, increment); } - INCR_SIZE = INCR_SIZE * 2; - if INCR_SIZE > MAX_EMALLOC_SIZE { - INCR_SIZE = MAX_EMALLOC_SIZE - }; + self.incr_size = (self.incr_size * 2).min(MAX_EMALLOC_SIZE); Ok(()) } + // Parsing the range of unmanaged memory. The function writes a chunk struct in the header of + // unmanaged memory, the written chunk will be responsible for managing the remaining memory. unsafe fn write_chunk(&mut self, base: usize, size: usize) { - let chunk: Chunk = Chunk::new(base, size); + let header_size = size_of::(); + let mem_base = base + header_size; + let mem_size = size - header_size; + + let chunk: Chunk = Chunk::new(mem_base, mem_size); unsafe { core::ptr::write(base as *mut Chunk, chunk); let chunk_ref = UnsafeRef::from_raw(base as *const Chunk); @@ -420,7 +463,7 @@ impl Reserve { } } - // find the chunk including the specified block: fn find_used_in_reserve + // Find the chunk including the specified block fn find_chunk_with_block( &mut self, block_addr: usize, @@ -432,12 +475,14 @@ impl Reserve { let mut cursor = self.chunks.front_mut(); while !cursor.is_null() { let chunk = cursor.get().unwrap(); - if block_addr >= chunk.base && block_addr + block_size <= chunk.base + chunk.used { + if (block_addr >= chunk.base) + && ((block_addr + block_size) <= (chunk.base + chunk.used)) + { return Ok(cursor); } cursor.move_next(); } - return Err(SgxStatus::InvalidParameter); + Err(SgxStatus::InvalidParameter) } } diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index 68fe33c7c..f11549fec 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -15,11 +15,20 @@ // specific language governing permissions and limitations // under the License.. +use self::{interior::init_alloc, range::init_range_manage, user::init_user_range}; + pub(crate) mod alloc; pub(crate) mod bitmap; pub(crate) mod ema; pub(crate) mod flags; #[cfg(not(any(feature = "sim", feature = "hyper")))] pub(crate) mod interior; +mod pfhandler; pub(crate) mod range; pub(crate) mod user; + +fn init_emm(user_start: usize, user_end: usize) { + init_user_range(user_start, user_end); + init_range_manage(); + init_alloc(); +} diff --git a/sgx_trts/src/emm/pfhandler.rs b/sgx_trts/src/emm/pfhandler.rs new file mode 100644 index 000000000..03d9cdbf8 --- /dev/null +++ b/sgx_trts/src/emm/pfhandler.rs @@ -0,0 +1,115 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +use crate::{ + edmm::ProtFlags, + emm::{ + flags::AllocFlags, + range::{RangeType, RM}, + }, + veh::HandleResult, +}; + +#[repr(C)] +pub struct PfInfo { + maddr: u64, // address for #PF. + pfec: Pfec, + reserved: u32, +} + +#[repr(C)] +union Pfec { + errcd: u32, + bits: PfecBits, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct PfecBits { + p: u32, // P flag. + rw: u32, // RW access flag, 0 for read, 1 for write. + reserved1: u32, + sgx: u32, // SGX bit. + reserved2: u32, +} + +impl Default for PfecBits { + fn default() -> Self { + Self { + p: 1, + rw: 1, + reserved1: 13, + sgx: 1, + reserved2: 16, + } + } +} + +pub type PfHandler = extern "C" fn(info: &mut PfInfo) -> HandleResult; + +extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { + let addr = trim_to_page!(info.maddr as usize); + let mut range_manage = RM.get().unwrap().lock(); + let mut ema_cursor = match range_manage.search_ema(addr, RangeType::User) { + Err(_) => { + let ema_cursor = range_manage.search_ema(addr, RangeType::Rts); + if ema_cursor.is_err() { + return HandleResult::Search; + } + ema_cursor.unwrap() + } + Ok(ema_cursor) => ema_cursor, + }; + + let ema = unsafe { ema_cursor.get_mut().unwrap() }; + let (handler, priv_data) = ema.fault_handler(); + if let Some(handler) = handler { + drop(range_manage); + let mut pf_info = unsafe { priv_data.unwrap().read() }; + return handler(&mut pf_info); + } + + // No customized page fault handler + if ema.is_page_committed(addr) { + // check spurious #pf + let rw_bit = unsafe { info.pfec.bits.rw }; + if (rw_bit == 0 && !ema.info().prot.contains(ProtFlags::R)) + || (rw_bit == 1 && !ema.info().prot.contains(ProtFlags::W)) + { + return HandleResult::Search; + } else { + return HandleResult::Execution; + } + } + + if ema.flags().contains(AllocFlags::COMMIT_ON_DEMAND) { + let rw_bit = unsafe { info.pfec.bits.rw }; + if (rw_bit == 0 && !ema.info().prot.contains(ProtFlags::R)) + || (rw_bit == 1 && !ema.info().prot.contains(ProtFlags::W)) + { + return HandleResult::Search; + }; + ema.commit_check() + .expect("The EPC page fails to meet the commit condition."); + ema.commit(addr, addr + crate::arch::SE_PAGE_SIZE) + .expect("The EPC page fails to be committed."); + HandleResult::Execution + } else { + // Some things are wrong + panic!() + } +} diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index c1c0b8a78..7a36d1c54 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -19,7 +19,6 @@ use crate::{ arch::SE_PAGE_SIZE, edmm::{PageInfo, PageType, ProtFlags}, enclave::is_within_enclave, - veh::{ExceptionHandler, ExceptionInfo}, }; use alloc::boxed::Box; use intrusive_collections::{linked_list::CursorMut, LinkedList, UnsafeRef}; @@ -30,7 +29,8 @@ use super::{ alloc::{ResAlloc, StaticAlloc}, ema::{EmaAda, EMA}, flags::AllocFlags, - interior::{Alloc, GLOBAL_LOCK}, + interior::Alloc, + pfhandler::{PfHandler, PfInfo}, user::{is_within_rts_range, is_within_user_range, USER_RANGE}, }; @@ -43,19 +43,20 @@ const PAGE_TYPE_MASK: usize = 0xFF << PAGE_TYPE_SHIFT; const ALLIGNMENT_SHIFT: usize = 24; const ALLIGNMENT_MASK: usize = 0xFF << ALLIGNMENT_SHIFT; -pub static mut RM: Once> = Once::new(); +pub static RM: Once> = Once::new(); +/// Initialize range management pub fn init_range_manage() { - unsafe { - RM.call_once(|| Mutex::new(RangeManage::new())); - } + RM.call_once(|| Mutex::new(RangeManage::new())); } +/// RangeManage manages virtual memory range pub struct RangeManage { user: LinkedList, rts: LinkedList, } +/// RangeType specifies using Rts or User range #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RangeType { @@ -71,15 +72,14 @@ impl RangeManage { } } - // Not considering concurrency and lock - // TODO: carefull examination !! + /// Allocate a new memory region in enclave address space (ELRANGE). pub fn alloc( &mut self, addr: Option, size: usize, flags: usize, - handler: Option, - priv_data: Option<*mut ExceptionInfo>, + handler: Option, + priv_data: Option<*mut PfInfo>, typ: RangeType, alloc: Alloc, ) -> SgxResult { @@ -131,23 +131,21 @@ impl RangeManage { if addr > 0 { let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); + // FIXME: search_ema_range implicitly contains splitting ema! let range = self.search_ema_range(addr, addr + size, typ, false); match range { // exist in emas list Ok(_) => { - // TODO: ema realloc from reserve - // If this ema can be reallocated, call allocation + // TODO: realloc EMA from reserve if is_fixed_alloc { - // FIXME: return EEXIST return Err(SgxStatus::InvalidParameter); } } // not exist in emas list Err(_) => { let next_ema = self.find_free_region_at(addr, size, typ); - // fixme: is_err - if next_ema.is_ok() && is_fixed_alloc { + if next_ema.is_err() && is_fixed_alloc { return Err(SgxStatus::InvalidParameter); } } @@ -194,16 +192,15 @@ impl RangeManage { }; next_ema.insert_before(new_ema_ref); - return Ok(free_addr); + Ok(free_addr) } - // Not considering concurrency and lock - // TODO: carefull examination !! + /// Commit a partial or full range of memory allocated previously with + /// COMMIT_ON_DEMAND. pub fn commit(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; - // check ema can commit let mut count = ema_num; while count != 0 { cursor.get().unwrap().commit_check()?; @@ -226,16 +223,30 @@ impl RangeManage { Ok(()) } + /// Deallocate the address range. pub fn dealloc(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { let (mut cursor, mut ema_num) = self.search_ema_range(addr, addr + size, typ, false)?; while ema_num != 0 { - unsafe { cursor.get_mut().unwrap().dealloc()? }; - cursor.move_next(); + // Calling remove() implicitly moves cursor pointing to next ema + let mut ema = cursor.remove().unwrap(); + ema.dealloc()?; + + // Drop inner EMA + match ema.allocator() { + Alloc::Reserve => { + let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), ResAlloc) }; + } + Alloc::Static => { + let _ema_box = + unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), StaticAlloc) }; + } + } ema_num -= 1; } Ok(()) } + /// Change the page type of an allocated region. pub fn modify_type( &mut self, addr: usize, @@ -251,14 +262,14 @@ impl RangeManage { return Err(SgxStatus::InvalidParameter); } - let (mut cursor, mut ema_num) = - self.search_ema_range(addr, addr + size, range_typ, true)?; + let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, range_typ, true)?; assert!(ema_num == 1); unsafe { cursor.get_mut().unwrap().change_to_tcs()? }; Ok(()) } + /// Change permissions of an allocated region. pub fn modify_perms( &mut self, addr: usize, @@ -276,7 +287,6 @@ impl RangeManage { let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; - // check ema can commit let mut count = ema_num; while count != 0 { cursor.get().unwrap().modify_perm_check()?; @@ -291,7 +301,7 @@ impl RangeManage { count = ema_num; while count != 0 { - unsafe { cursor.get_mut().unwrap().modify_perm(prot) }; + unsafe { cursor.get_mut().unwrap().modify_perm(prot)? }; cursor.move_next(); count -= 1; } @@ -299,11 +309,11 @@ impl RangeManage { Ok(()) } + /// Uncommit (trim) physical EPC pages in a previously committed range. pub fn uncommit(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; - // check ema can commit let mut count = ema_num; while count != 0 { cursor.get().unwrap().uncommit_check()?; @@ -318,7 +328,7 @@ impl RangeManage { count = ema_num; while count != 0 { - unsafe { cursor.get_mut().unwrap().uncommit_self() }; + unsafe { cursor.get_mut().unwrap().uncommit_self()? }; cursor.move_next(); count -= 1; } @@ -370,8 +380,6 @@ impl RangeManage { cursor.move_next(); } - drop(cursor); - let mut end_ema_ptr = curr_ema as *const EMA; // Found the overlapping emas with range [start, end) @@ -398,7 +406,6 @@ impl RangeManage { if emas_num == 1 { end_ema_ptr = start_ema_ptr; } - drop(start_cursor); // Spliting end ema let mut end_cursor = match typ { @@ -414,7 +421,6 @@ impl RangeManage { let right_ema_ref = unsafe { UnsafeRef::from_raw(right_ema) }; end_cursor.insert_after(right_ema_ref); } - drop(end_cursor); // Recover start ema and return it as range let start_cursor = match typ { @@ -422,7 +428,25 @@ impl RangeManage { RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, }; - return Ok((start_cursor, emas_num)); + Ok((start_cursor, emas_num)) + } + + // search for a ema node whose memory range contains address + pub fn search_ema(&mut self, addr: usize, typ: RangeType) -> SgxResult> { + let mut cursor = match typ { + RangeType::Rts => self.rts.front_mut(), + RangeType::User => self.user.front_mut(), + }; + + while !cursor.is_null() { + let ema = cursor.get().unwrap(); + if ema.overlap_addr(addr) { + return Ok(cursor); + } + cursor.move_next(); + } + + Err(SgxStatus::InvalidParameter) } // Find a free space at addr with 'len' bytes in reserve region, @@ -474,7 +498,7 @@ impl RangeManage { return Ok(cursor); } - return Err(SgxStatus::InvalidParameter); + Err(SgxStatus::InvalidParameter) } // Find a free space of size at least 'size' bytes in reserve region, @@ -489,7 +513,7 @@ impl RangeManage { let user_base = user_range.start; let user_end = user_range.end; - let mut addr = 0; + let mut addr; let mut cursor: CursorMut<'_, EmaAda> = match typ { RangeType::Rts => self.rts.front_mut(), @@ -534,11 +558,11 @@ impl RangeManage { if curr_end <= next_start { let free_size = next_start - curr_end; - if free_size >= len { - if typ == RangeType::User || is_within_rts_range(curr_end, len) { - cursor.move_next(); - return Ok((curr_end, cursor)); - } + if free_size >= len + && (typ == RangeType::User || is_within_rts_range(curr_end, len)) + { + cursor.move_next(); + return Ok((curr_end, cursor)); } } cursor.move_next(); @@ -547,13 +571,12 @@ impl RangeManage { addr = cursor.get().map(|ema| ema.aligned_end(align)).unwrap(); - if is_within_enclave(addr as *const u8, len) { - if (typ == RangeType::Rts && is_within_rts_range(addr, len)) - || (typ == RangeType::User && is_within_user_range(addr, len)) - { - cursor.move_next(); - return Ok((addr, cursor)); - } + if is_within_enclave(addr as *const u8, len) + && ((typ == RangeType::Rts && is_within_rts_range(addr, len)) + || (typ == RangeType::User && is_within_user_range(addr, len))) + { + cursor.move_next(); + return Ok((addr, cursor)); } // Cursor moves to emas->front_mut. diff --git a/sgx_trts/src/emm/user.rs b/sgx_trts/src/emm/user.rs index 25cf96c9e..85baaff40 100644 --- a/sgx_trts/src/emm/user.rs +++ b/sgx_trts/src/emm/user.rs @@ -32,10 +32,10 @@ impl UserRange { } } +/// User memory range specified by SDK developer pub static USER_RANGE: Once = Once::new(); -pub fn init_range(start: usize, end: usize) { - // init +pub fn init_user_range(start: usize, end: usize) { let _ = *USER_RANGE.call_once(|| UserRange { start, end }); } diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs index 69cb8283d..32c84dc1a 100644 --- a/sgx_trts/src/lib.rs +++ b/sgx_trts/src/lib.rs @@ -38,6 +38,7 @@ #![allow(non_camel_case_types)] #![feature(linked_list_cursors)] #![feature(strict_provenance)] +#![feature(pointer_byte_offsets)] #[cfg(all(feature = "sim", feature = "hyper"))] compile_error!("feature \"sim\" and feature \"hyper\" cannot be enabled at the same time"); From 9ac48b2c7def8a9722eee848369724968c22c79a Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Tue, 29 Aug 2023 17:32:12 +0800 Subject: [PATCH 05/20] Couple EMM with rt initialization --- sgx_trts/src/edmm/mem.rs | 41 +++++++++ sgx_trts/src/emm/alloc.rs | 17 ++++ sgx_trts/src/emm/bitmap.rs | 1 + sgx_trts/src/emm/ema.rs | 21 ++++- sgx_trts/src/emm/flags.rs | 25 +----- sgx_trts/src/emm/init.rs | 152 +++++++++++++++++++++++++++++++++ sgx_trts/src/emm/mod.rs | 9 +- sgx_trts/src/emm/range.rs | 158 ++++++++++++++++++++++++++++++++++- sgx_trts/src/enclave/init.rs | 25 ++++-- sgx_trts/src/lib.rs | 1 - 10 files changed, 405 insertions(+), 45 deletions(-) create mode 100644 sgx_trts/src/emm/init.rs diff --git a/sgx_trts/src/edmm/mem.rs b/sgx_trts/src/edmm/mem.rs index 18b1581d5..7eaeecb7a 100644 --- a/sgx_trts/src/edmm/mem.rs +++ b/sgx_trts/src/edmm/mem.rs @@ -31,6 +31,8 @@ mod hw { use crate::edmm::perm; use crate::edmm::trim; use crate::elf::program::Type; + use crate::emm::flags::AllocFlags; + use crate::emm::range::RM; use crate::enclave::parse; use crate::enclave::MmLayout; use crate::feature::{SysFeatures, Version}; @@ -190,6 +192,45 @@ mod hw { Ok(()) } + pub fn init_segment_emas() -> SgxResult { + let elf = parse::new_elf()?; + let text_relo = parse::has_text_relo()?; + + let base = MmLayout::image_base(); + for phdr in elf.program_iter() { + let typ = phdr.get_type().unwrap_or(Type::Null); + + if typ == Type::Load { + let mut perm = ProtFlags::R; + let start = base + trim_to_page!(phdr.virtual_addr() as usize); + let end = + base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); + + if phdr.flags().is_write() || text_relo { + perm |= ProtFlags::W; + } + if phdr.flags().is_execute() { + perm |= ProtFlags::X; + } + + let mut range_manage = RM.get().unwrap().lock(); + range_manage.init_static_region( + start, + end - start, + AllocFlags::SYSTEM, + PageInfo { + typ: PageType::Reg, + prot: perm, + }, + None, + None, + )?; + } + } + + Ok(()) + } + fn modify_perm(addr: usize, count: usize, perm: u8) -> SgxResult { let pages = PageRange::new( addr, diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index dde3b5c85..dee4a9c39 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -1,3 +1,20 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + use core::alloc::{AllocError, Allocator, Layout}; use core::ptr::NonNull; diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index 479747a39..9eb6cbaec 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -14,6 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License.. + use alloc::boxed::Box; use alloc::vec; use core::alloc::Allocator; diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index 62bb45b06..3c489527c 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -77,7 +77,7 @@ impl EMA { alloc: Alloc, ) -> SgxResult { // check alloc flags' eligibility - AllocFlags::try_from(alloc_flags.bits())?; + // AllocFlags::try_from(alloc_flags.bits())?; if start != 0 && length != 0 @@ -576,6 +576,25 @@ impl EMA { (addr >= self.start) && (addr < self.start + self.length) } + pub fn set_eaccept_map_full(&mut self) -> SgxResult { + if self.eaccept_map.is_none() { + let eaccept_map = match self.alloc { + Alloc::Reserve => { + let page_num = self.length >> SE_PAGE_SHIFT; + BitArray::new(page_num, Alloc::Reserve)? + } + Alloc::Static => { + let page_num = self.length >> SE_PAGE_SHIFT; + BitArray::new(page_num, Alloc::Static)? + } + }; + self.eaccept_map = Some(eaccept_map); + } else { + self.eaccept_map.as_mut().unwrap().set_full(); + } + Ok(()) + } + fn set_flags(&mut self, flags: AllocFlags) { self.alloc_flags = flags; } diff --git a/sgx_trts/src/emm/flags.rs b/sgx_trts/src/emm/flags.rs index 1d278170c..55e6c3ce3 100644 --- a/sgx_trts/src/emm/flags.rs +++ b/sgx_trts/src/emm/flags.rs @@ -16,7 +16,6 @@ // under the License.. use bitflags::bitflags; -use sgx_types::error::{SgxResult, SgxStatus}; bitflags! { pub struct AllocFlags: u32 { @@ -26,28 +25,6 @@ bitflags! { const GROWSDOWN = 0b00010000; const GROWSUP = 0b00100000; const FIXED = 0b01000000; - } -} - -impl AllocFlags { - pub fn try_from(value: u32) -> SgxResult { - match value { - 0b0000_0001 => Ok(Self::RESERVED), - 0b0000_0010 => Ok(Self::COMMIT_NOW), - 0b0000_0100 => Ok(Self::COMMIT_ON_DEMAND), - 0b0001_0000 => Ok(Self::GROWSDOWN), - 0b0010_0000 => Ok(Self::GROWSUP), - 0b0100_0000 => Ok(Self::FIXED), - 0b0001_0001 => Ok(Self::RESERVED | Self::GROWSDOWN), - 0b0010_0001 => Ok(Self::RESERVED | Self::GROWSUP), - 0b0100_0001 => Ok(Self::RESERVED | Self::FIXED), - 0b0001_0010 => Ok(Self::COMMIT_NOW | Self::GROWSDOWN), - 0b0010_0010 => Ok(Self::COMMIT_NOW | Self::GROWSUP), - 0b0100_0010 => Ok(Self::COMMIT_NOW | Self::FIXED), - 0b0001_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::GROWSDOWN), - 0b0010_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::GROWSUP), - 0b0100_0100 => Ok(Self::COMMIT_ON_DEMAND | Self::FIXED), - _ => Err(SgxStatus::InvalidParameter), - } + const SYSTEM = 0b10000000; } } diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs new file mode 100644 index 000000000..01a22a937 --- /dev/null +++ b/sgx_trts/src/emm/init.rs @@ -0,0 +1,152 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +use sgx_types::error::SgxResult; + +use crate::arch::{Layout, LayoutEntry}; +use crate::edmm::mem::init_segment_emas; +use crate::edmm::{PageInfo, PageType, ProtFlags}; +use crate::emm::flags::AllocFlags; +use crate::emm::interior::Alloc; +use crate::emm::range::{RangeType, EMA_PROT_MASK}; +use crate::enclave::MmLayout; +use crate::{arch, emm::range::RM}; + +use super::{interior::init_alloc, range::init_range_manage, user::init_user_range}; + +pub fn init_emm(user_start: usize, user_end: usize) { + // check user_start not equals to 0 + init_user_range(user_start, user_end); + init_range_manage(); + init_alloc(); +} + +pub fn init_rts_emas() -> SgxResult { + init_segment_emas()?; + init_rts_contexts_emas(arch::Global::get().layout_table(), 0)?; + Ok(()) +} + +fn init_rts_contexts_emas(table: &[Layout], offset: usize) -> SgxResult { + unsafe { + for (i, layout) in table.iter().enumerate() { + if is_group_id!(layout.group.id) { + let mut step = 0_usize; + for _ in 0..layout.group.load_times { + step += layout.group.load_step as usize; + init_rts_contexts_emas(&table[i - layout.group.entry_count as usize..i], step)?; + } + } else { + build_rts_context_emas(&layout.entry, offset)?; + } + } + Ok(()) + } +} + +fn build_rts_context_emas(entry: &LayoutEntry, offset: usize) -> SgxResult { + let rva = offset + (entry.rva as usize); + assert!(is_page_aligned!(rva)); + + // TODO: not sure get_enclave_base() equal to elrange_base or image_base + let addr = MmLayout::elrange_base() + (rva as usize); + let size = (entry.page_count << arch::SE_PAGE_SHIFT) as usize; + let mut range_manage = RM.get().unwrap().lock(); + + // entry is guard page or has EREMOVE, build a reserved ema + if (entry.si_flags == 0) || (entry.attributes & arch::PAGE_ATTR_EREMOVE != 0) { + range_manage.init_static_region( + addr, + size, + AllocFlags::RESERVED | AllocFlags::SYSTEM, + PageInfo { + typ: PageType::None, + prot: ProtFlags::NONE, + }, + None, + None, + )?; + return Ok(()); + } + + let post_remove = (entry.attributes & arch::PAGE_ATTR_POST_REMOVE) != 0; + let post_add = (entry.attributes & arch::PAGE_ATTR_POST_ADD) != 0; + let static_min = (entry.attributes & arch::PAGE_ATTR_EADD) != 0; + + if post_remove { + // TODO: maybe AllocFlags need more flags or PageType is not None + range_manage.init_static_region( + addr, + size, + AllocFlags::SYSTEM, + PageInfo { + typ: PageType::None, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + )?; + + range_manage.dealloc(addr, size, RangeType::Rts)?; + } + + if post_add { + let commit_direction = if entry.id == arch::LAYOUT_ID_STACK_MAX + || entry.id == arch::LAYOUT_ID_STACK_DYN_MAX + || entry.id == arch::LAYOUT_ID_STACK_DYN_MIN + { + AllocFlags::GROWSDOWN + } else { + AllocFlags::GROWSUP + }; + + // TODO: revise alloc and not use int + range_manage.alloc_inner( + Some(addr), + size, + AllocFlags::COMMIT_ON_DEMAND + | commit_direction + | AllocFlags::SYSTEM + | AllocFlags::FIXED, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + RangeType::Rts, + Alloc::Reserve, + )?; + } else if static_min { + let info = if entry.id == arch::LAYOUT_ID_TCS { + PageInfo { + typ: PageType::Tcs, + prot: ProtFlags::NONE, + } + } else { + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::from_bits_truncate( + (entry.si_flags as usize & EMA_PROT_MASK) as u8, + ), + } + }; + range_manage.init_static_region(addr, size, AllocFlags::SYSTEM, info, None, None)?; + } + + Ok(()) +} diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index f11549fec..92e602882 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -15,20 +15,13 @@ // specific language governing permissions and limitations // under the License.. -use self::{interior::init_alloc, range::init_range_manage, user::init_user_range}; - pub(crate) mod alloc; pub(crate) mod bitmap; pub(crate) mod ema; pub(crate) mod flags; +pub(crate) mod init; #[cfg(not(any(feature = "sim", feature = "hyper")))] pub(crate) mod interior; mod pfhandler; pub(crate) mod range; pub(crate) mod user; - -fn init_emm(user_start: usize, user_end: usize) { - init_user_range(user_start, user_end); - init_range_manage(); - init_alloc(); -} diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index 7a36d1c54..e185bc2bf 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -19,11 +19,12 @@ use crate::{ arch::SE_PAGE_SIZE, edmm::{PageInfo, PageType, ProtFlags}, enclave::is_within_enclave, + sync::SpinReentrantMutex, }; use alloc::boxed::Box; use intrusive_collections::{linked_list::CursorMut, LinkedList, UnsafeRef}; use sgx_types::error::{SgxResult, SgxStatus}; -use spin::{Mutex, Once}; +use spin::Once; use super::{ alloc::{ResAlloc, StaticAlloc}, @@ -43,11 +44,13 @@ const PAGE_TYPE_MASK: usize = 0xFF << PAGE_TYPE_SHIFT; const ALLIGNMENT_SHIFT: usize = 24; const ALLIGNMENT_MASK: usize = 0xFF << ALLIGNMENT_SHIFT; -pub static RM: Once> = Once::new(); +pub const EMA_PROT_MASK: usize = 0x7; + +pub static RM: Once> = Once::new(); /// Initialize range management pub fn init_range_manage() { - RM.call_once(|| Mutex::new(RangeManage::new())); + RM.call_once(|| SpinReentrantMutex::new(RangeManage::new())); } /// RangeManage manages virtual memory range @@ -72,6 +75,47 @@ impl RangeManage { } } + // Reserve memory range for allocations created + // by the RTS enclave loader at fixed address ranges + pub fn init_static_region( + &mut self, + addr: usize, + size: usize, + alloc_flags: AllocFlags, + info: PageInfo, + handler: Option, + priv_data: Option<*mut PfInfo>, + ) -> SgxResult { + ensure!( + addr != 0 && size != 0 && is_within_enclave(addr as *const u8, size), + SgxStatus::InvalidParameter + ); + + let mut next_ema = self.find_free_region_at(addr, size, RangeType::Rts)?; + + let mut new_ema = Box::::new_in( + EMA::new( + addr, + size, + alloc_flags, + info, + handler, + priv_data, + Alloc::Reserve, + )?, + ResAlloc, + ); + // new_ema.alloc()?; + if !alloc_flags.contains(AllocFlags::RESERVED) { + new_ema.set_eaccept_map_full()?; + } + + let new_ema_ref = unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) }; + next_ema.insert_before(new_ema_ref); + + Ok(()) + } + /// Allocate a new memory region in enclave address space (ELRANGE). pub fn alloc( &mut self, @@ -84,8 +128,18 @@ impl RangeManage { alloc: Alloc, ) -> SgxResult { let addr = addr.unwrap_or(0); + // let alloc_flags = + // AllocFlags::try_from(((flags & ALLOC_FLAGS_MASK) >> ALLOC_FLAGS_SHIFT) as u32)?; + let alloc_flags = - AllocFlags::try_from(((flags & ALLOC_FLAGS_MASK) >> ALLOC_FLAGS_SHIFT) as u32)?; + AllocFlags::from_bits(((flags & ALLOC_FLAGS_MASK) >> ALLOC_FLAGS_SHIFT) as u32) + .ok_or(SgxStatus::InvalidParameter)?; + + // TODO: uncouple EMA and range management + // if alloc_flags.contains(AllocFlags::SYSTEM) { + // return Err(SgxStatus::InvalidParameter); + // } + let mut page_type = match PageType::try_from(((flags & PAGE_TYPE_MASK) >> PAGE_TYPE_SHIFT) as u8) { Ok(typ) => typ, @@ -157,6 +211,23 @@ impl RangeManage { let new_ema_ref = match alloc { Alloc::Reserve => { let mut new_ema = Box::::new_in( + EMA::new( + free_addr, + size, + alloc_flags, + info, + handler, + priv_data, + Alloc::Reserve, + )?, + ResAlloc, + ); + new_ema.alloc()?; + + unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } + } + Alloc::Static => { + let mut new_ema = Box::::new_in( EMA::new( free_addr, size, @@ -166,6 +237,85 @@ impl RangeManage { priv_data, Alloc::Static, )?, + StaticAlloc, + ); + new_ema.alloc()?; + + unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } + } + }; + + next_ema.insert_before(new_ema_ref); + Ok(free_addr) + } + + /// Allocate a new memory region in enclave address space (ELRANGE). + pub fn alloc_inner( + &mut self, + addr: Option, + size: usize, + alloc_flags: AllocFlags, + info: PageInfo, + handler: Option, + priv_data: Option<*mut PfInfo>, + typ: RangeType, + alloc: Alloc, + ) -> SgxResult { + let addr = addr.unwrap_or(0); + + // Default align is 12 + let align_flag = 12; + let align_mask: usize = (1 << align_flag) - 1; + + if (size % SE_PAGE_SIZE) > 0 { + return Err(SgxStatus::InvalidParameter); + } + + if (addr & align_mask) > 0 { + return Err(SgxStatus::InvalidParameter); + } + + if (addr > 0) && !is_within_enclave(addr as *const u8, size) { + return Err(SgxStatus::InvalidParameter); + } + + if addr > 0 { + let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); + // FIXME: search_ema_range implicitly contains splitting ema! + let range = self.search_ema_range(addr, addr + size, typ, false); + + match range { + // exist in emas list + Ok(_) => { + // TODO: realloc EMA from reserve + if is_fixed_alloc { + return Err(SgxStatus::InvalidParameter); + } + } + // not exist in emas list + Err(_) => { + let next_ema = self.find_free_region_at(addr, size, typ); + if next_ema.is_err() && is_fixed_alloc { + return Err(SgxStatus::InvalidParameter); + } + } + }; + }; + + let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; + + let new_ema_ref = match alloc { + Alloc::Reserve => { + let mut new_ema = Box::::new_in( + EMA::new( + free_addr, + size, + alloc_flags, + info, + handler, + priv_data, + Alloc::Reserve, + )?, ResAlloc, ); new_ema.alloc()?; diff --git a/sgx_trts/src/enclave/init.rs b/sgx_trts/src/enclave/init.rs index 1e61526d0..0ee5333fe 100644 --- a/sgx_trts/src/enclave/init.rs +++ b/sgx_trts/src/enclave/init.rs @@ -16,6 +16,7 @@ // under the License.. use crate::arch::Tcs; +use crate::emm::init::{init_emm, init_rts_emas}; use crate::enclave::state::State; use crate::enclave::EnclaveRange; use crate::enclave::{mem, parse, state}; @@ -80,19 +81,29 @@ pub fn rtinit(tcs: &mut Tcs, ms: *mut SystemFeatures, tidx: usize) -> SgxResult tc::ThreadControl::from_tcs(tcs).init(tidx, true)?; + // #[cfg(not(any(feature = "sim", feature = "hyper")))] + // { + // if features.is_edmm() { + // // EDMM: + // // need to accept the trimming of the POST_REMOVE pages + // crate::edmm::mem::accept_post_remove()?; + // } + // } + + heap.zero_memory(); + rsrvmem.zero_memory(); + + state::set_state(State::InitDone); + #[cfg(not(any(feature = "sim", feature = "hyper")))] { if features.is_edmm() { - // EDMM: - // need to accept the trimming of the POST_REMOVE pages - crate::edmm::mem::accept_post_remove()?; + let usermem = mem::UserRegionMem::get_or_init(); + init_emm(usermem.base, usermem.base + usermem.size); + init_rts_emas()?; } } - heap.zero_memory(); - rsrvmem.zero_memory(); - - state::set_state(State::InitDone); Ok(()) } diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs index 32c84dc1a..5071f0a76 100644 --- a/sgx_trts/src/lib.rs +++ b/sgx_trts/src/lib.rs @@ -70,7 +70,6 @@ pub mod emm; #[cfg(not(any(feature = "sim", feature = "hyper")))] pub mod aexnotify; -pub mod edmm; pub mod error; #[macro_use] pub mod feature; From 23db3885372589ed5e939822524b1550d7a153f8 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Thu, 31 Aug 2023 08:05:14 +0000 Subject: [PATCH 06/20] Couple pf handler with veh --- sgx_rsrvmm/src/rsrvmm/area.rs | 4 +-- sgx_trts/src/emm/init.rs | 2 +- sgx_trts/src/emm/mod.rs | 2 +- sgx_trts/src/emm/pfhandler.rs | 66 ++++++++++++++++++++++++----------- sgx_trts/src/veh/exception.rs | 13 ++++--- 5 files changed, 58 insertions(+), 29 deletions(-) diff --git a/sgx_rsrvmm/src/rsrvmm/area.rs b/sgx_rsrvmm/src/rsrvmm/area.rs index 177653031..10840043a 100644 --- a/sgx_rsrvmm/src/rsrvmm/area.rs +++ b/sgx_rsrvmm/src/rsrvmm/area.rs @@ -25,7 +25,7 @@ use core::convert::From; use core::fmt; use core::ops::{Deref, DerefMut}; use sgx_trts::edmm::{modpr_ocall, mprotect_ocall}; -use sgx_trts::edmm::{PageFlags, PageInfo, PageRange, PageType}; +use sgx_trts::edmm::{ProtFlags, PageInfo, PageRange, PageType}; use sgx_trts::trts; use sgx_types::error::errno::*; use sgx_types::error::OsResult; @@ -364,7 +364,7 @@ impl MmArea { count, PageInfo { typ: PageType::Reg, - flags: PageFlags::from_bits_truncate(perm.into()) | PageFlags::PR, + prot: ProtFlags::from_bits_truncate(perm.into()) | ProtFlags::PR, }, ) .map_err(|_| EINVAL)?; diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs index 01a22a937..37b3094ea 100644 --- a/sgx_trts/src/emm/init.rs +++ b/sgx_trts/src/emm/init.rs @@ -63,7 +63,7 @@ fn build_rts_context_emas(entry: &LayoutEntry, offset: usize) -> SgxResult { assert!(is_page_aligned!(rva)); // TODO: not sure get_enclave_base() equal to elrange_base or image_base - let addr = MmLayout::elrange_base() + (rva as usize); + let addr = MmLayout::image_base() + (rva as usize); let size = (entry.page_count << arch::SE_PAGE_SHIFT) as usize; let mut range_manage = RM.get().unwrap().lock(); diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index 92e602882..35a137fd0 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -22,6 +22,6 @@ pub(crate) mod flags; pub(crate) mod init; #[cfg(not(any(feature = "sim", feature = "hyper")))] pub(crate) mod interior; -mod pfhandler; +pub(crate) mod pfhandler; pub(crate) mod range; pub(crate) mod user; diff --git a/sgx_trts/src/emm/pfhandler.rs b/sgx_trts/src/emm/pfhandler.rs index 03d9cdbf8..edd507580 100644 --- a/sgx_trts/src/emm/pfhandler.rs +++ b/sgx_trts/src/emm/pfhandler.rs @@ -37,31 +37,55 @@ union Pfec { bits: PfecBits, } -#[repr(C)] -#[derive(Debug, Clone, Copy)] -struct PfecBits { - p: u32, // P flag. - rw: u32, // RW access flag, 0 for read, 1 for write. - reserved1: u32, - sgx: u32, // SGX bit. - reserved2: u32, -} +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +struct PfecBits(u32); -impl Default for PfecBits { - fn default() -> Self { - Self { - p: 1, - rw: 1, - reserved1: 13, - sgx: 1, - reserved2: 16, - } +impl PfecBits { + const P_OFFSET: u32 = 0; + const P_MASK: u32 = 0x00000001; + const RW_OFFSET: u32 = 1; + const RW_MASK: u32 = 0x00000002; + const SGX_OFFSET: u32 = 15; + const SGX_MASK: u32 = 0x00008000; + + #[inline] + pub fn p(&self) -> u32 { + (self.0 & Self::P_MASK) >> Self::P_OFFSET + } + + #[inline] + pub fn rw(&self) -> u32 { + (self.0 & Self::RW_MASK) >> Self::RW_OFFSET + } + + #[inline] + pub fn sgx(&self) -> u32 { + (self.0 & Self::SGX_MASK) >> Self::SGX_OFFSET + } + + #[inline] + pub fn set_p(&mut self, p: u32) { + let p = (p << Self::P_OFFSET) & Self::P_MASK; + self.0 = (self.0 & (!Self::P_MASK)) | p; + } + + #[inline] + pub fn set_rw(&mut self, rw: u32) { + let rw = (rw << Self::RW_OFFSET) & Self::RW_MASK; + self.0 = (self.0 & (!Self::RW_MASK)) | rw; + } + + #[inline] + pub fn set_sgx(&mut self, sgx: u32) { + let sgx = (sgx << Self::SGX_OFFSET) & Self::SGX_MASK; + self.0 = (self.0 & (!Self::SGX_MASK)) | sgx; } } pub type PfHandler = extern "C" fn(info: &mut PfInfo) -> HandleResult; -extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { +pub extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { let addr = trim_to_page!(info.maddr as usize); let mut range_manage = RM.get().unwrap().lock(); let mut ema_cursor = match range_manage.search_ema(addr, RangeType::User) { @@ -86,7 +110,7 @@ extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { // No customized page fault handler if ema.is_page_committed(addr) { // check spurious #pf - let rw_bit = unsafe { info.pfec.bits.rw }; + let rw_bit = unsafe { info.pfec.bits.rw() }; if (rw_bit == 0 && !ema.info().prot.contains(ProtFlags::R)) || (rw_bit == 1 && !ema.info().prot.contains(ProtFlags::W)) { @@ -97,7 +121,7 @@ extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { } if ema.flags().contains(AllocFlags::COMMIT_ON_DEMAND) { - let rw_bit = unsafe { info.pfec.bits.rw }; + let rw_bit = unsafe { info.pfec.bits.rw() }; if (rw_bit == 0 && !ema.info().prot.contains(ProtFlags::R)) || (rw_bit == 1 && !ema.info().prot.contains(ProtFlags::W)) { diff --git a/sgx_trts/src/veh/exception.rs b/sgx_trts/src/veh/exception.rs index d24f11e25..220567125 100644 --- a/sgx_trts/src/veh/exception.rs +++ b/sgx_trts/src/veh/exception.rs @@ -17,12 +17,14 @@ use crate::arch::{self, MiscExInfo, SsaGpr, Tcs, Tds}; use crate::edmm; +use crate::emm::pfhandler::{mm_enclave_pfhandler, PfInfo}; use crate::enclave::state::{self, State}; use crate::error; use crate::feature::SysFeatures; use crate::tcs::tc::{self, ThreadControl}; use crate::trts; use crate::veh::list; +use crate::veh::register; use crate::veh::MAX_REGISTER_COUNT; use crate::veh::{ExceptionHandler, ExceptionInfo, ExceptionType, ExceptionVector, HandleResult}; use crate::xsave; @@ -307,10 +309,13 @@ extern "C" fn internal_handle(info: &mut ExceptionInfo) { if info.vector == ExceptionVector::PF { tds.exception_flag -= 1; - // EMM_TODO: - // if mm_fault_handler(&info.exinfo) == SGX_MM_EXCEPTION_CONTINUE_EXECUTION { - // exception_continue_execution(info); - // } + let pfinfo = + unsafe { &mut *(&mut info.exinfo as *mut register::MiscExInfo as *mut PfInfo) }; + + if mm_enclave_pfhandler(pfinfo) == HandleResult::Execution { + exception_continue_execution(info, tds); + } + tds.exception_flag += 1; } From a4d9c592d537a76c11c8a270e7461689e58b2238 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 15 Sep 2023 02:43:40 +0000 Subject: [PATCH 07/20] Merge EMM in SDK and fix trivial bugs --- sgx_trts/src/arch.rs | 8 +++ sgx_trts/src/asm/pic.S | 2 +- sgx_trts/src/call/ecall.rs | 4 ++ sgx_trts/src/edmm/mem.rs | 58 ++++------------ sgx_trts/src/edmm/tcs.rs | 51 +++++--------- sgx_trts/src/emm/bitmap.rs | 3 +- sgx_trts/src/emm/ema.rs | 74 +++++++++++--------- sgx_trts/src/emm/init.rs | 25 ++++--- sgx_trts/src/emm/interior.rs | 12 +--- sgx_trts/src/emm/range.rs | 123 ++++++++++++++++++++++++++------- sgx_trts/src/emm/user.rs | 41 +++-------- sgx_trts/src/enclave/init.rs | 12 +--- sgx_trts/src/enclave/uninit.rs | 27 ++++++-- sgx_trts/src/tcs/tc.rs | 2 +- 14 files changed, 239 insertions(+), 203 deletions(-) diff --git a/sgx_trts/src/arch.rs b/sgx_trts/src/arch.rs index d98c03118..68b439ec0 100644 --- a/sgx_trts/src/arch.rs +++ b/sgx_trts/src/arch.rs @@ -566,6 +566,14 @@ pub const SI_FLAGS_SECS: u64 = SI_FLAG_SECS; pub const SI_MASK_TCS: u64 = SI_FLAG_PT_MASK; pub const SI_MASK_MEM_ATTRIBUTE: u64 = 0x7; +pub const SGX_EMA_PROT_NONE: u64 = 0x0; +pub const SGX_EMA_PROT_READ: u64 = 0x1; +pub const SGX_EMA_PROT_WRITE: u64 = 0x2; +pub const SGX_EMA_PROT_EXEC: u64 = 0x4; +pub const SGX_EMA_PROT_READ_WRITE: u64 = SGX_EMA_PROT_READ | SGX_EMA_PROT_WRITE; +pub const SGX_EMA_PROT_READ_EXEC: u64 = SGX_EMA_PROT_READ | SGX_EMA_PROT_EXEC; +pub const SGX_EMA_PROT_READ_WRITE_EXEC: u64 = SGX_EMA_PROT_READ_WRITE | SGX_EMA_PROT_EXEC; + #[repr(C, packed)] #[derive(Clone, Copy)] pub struct OCallContext { diff --git a/sgx_trts/src/asm/pic.S b/sgx_trts/src/asm/pic.S index 47cea6cda..cffd92129 100644 --- a/sgx_trts/src/asm/pic.S +++ b/sgx_trts/src/asm/pic.S @@ -24,7 +24,7 @@ __ImageBase: .equ SE_GUARD_PAGE_SHIFT, 16 .equ SE_GUARD_PAGE_SIZE, (1 << SE_GUARD_PAGE_SHIFT) .equ RED_ZONE_SIZE, 128 -.equ STATIC_STACK_SIZE, 2656 +.equ STATIC_STACK_SIZE, 4096 .equ OCMD_ERET, -1 diff --git a/sgx_trts/src/call/ecall.rs b/sgx_trts/src/call/ecall.rs index c9c2f5025..05b8f88ce 100644 --- a/sgx_trts/src/call/ecall.rs +++ b/sgx_trts/src/call/ecall.rs @@ -272,6 +272,7 @@ pub fn ecall(idx: ECallIndex, tcs: &mut Tcs, ms: *mut T, tidx: usize) -> SgxR ensure!(is_root_ecall, SgxStatus::ECallNotAllowed); FIRST_ECALL.call_once(|| { + debug_call_once(); // EDMM: #[cfg(not(any(feature = "sim", feature = "hyper")))] { @@ -353,3 +354,6 @@ pub fn thread_is_exit() -> bool { } } } + +#[no_mangle] +pub extern "C" fn debug_call_once() {} diff --git a/sgx_trts/src/edmm/mem.rs b/sgx_trts/src/edmm/mem.rs index 7eaeecb7a..e32256f84 100644 --- a/sgx_trts/src/edmm/mem.rs +++ b/sgx_trts/src/edmm/mem.rs @@ -28,17 +28,13 @@ mod hw { use crate::arch::{self, Layout}; use crate::edmm::epc::{PageInfo, PageRange, PageType, ProtFlags}; use crate::edmm::layout::LayoutTable; - use crate::edmm::perm; use crate::edmm::trim; use crate::elf::program::Type; use crate::emm::flags::AllocFlags; - use crate::emm::range::RM; + use crate::emm::range::{RangeType, RM}; use crate::enclave::parse; use crate::enclave::MmLayout; - use crate::feature::{SysFeatures, Version}; - use core::convert::TryFrom; use sgx_types::error::{SgxResult, SgxStatus}; - use sgx_types::types::ProtectPerm; pub fn apply_epc_pages(addr: usize, count: usize) -> SgxResult { ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); @@ -93,15 +89,8 @@ mod hw { .check_dyn_range(addr, count, None) .ok_or(SgxStatus::InvalidParameter)?; - let pages = PageRange::new( - addr, - count, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, - }, - )?; - pages.accept_forward()?; + let mut range_manage = RM.get().unwrap().lock(); + range_manage.commit(addr, count << arch::SE_PAGE_SHIFT, RangeType::Rts)?; Ok(()) } @@ -148,6 +137,7 @@ mod hw { let text_relo = parse::has_text_relo()?; let base = MmLayout::image_base(); + let mut range_manage = RM.get().unwrap().lock(); for phdr in elf.program_iter() { let typ = phdr.get_type().unwrap_or(Type::Null); if typ == Type::Load && text_relo && !phdr.flags().is_write() { @@ -155,25 +145,26 @@ mod hw { let start = base + trim_to_page!(phdr.virtual_addr() as usize); let end = base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); - let count = (end - start) / arch::SE_PAGE_SIZE; + let size = end - start; if phdr.flags().is_read() { - perm |= arch::SI_FLAG_R; + perm |= arch::SGX_EMA_PROT_READ; } if phdr.flags().is_execute() { - perm |= arch::SI_FLAG_X; + perm |= arch::SGX_EMA_PROT_EXEC; } - modify_perm(start, count, perm as u8)?; + let prot = ProtFlags::from_bits_truncate(perm as u8); + range_manage.modify_perms(start, size, prot, RangeType::Rts)?; } if typ == Type::GnuRelro { let start = base + trim_to_page!(phdr.virtual_addr() as usize); let end = base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); - let count = (end - start) / arch::SE_PAGE_SIZE; + let size = end - start; - if count > 0 { - modify_perm(start, count, arch::SI_FLAG_R as u8)?; + if size > 0 { + range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; } } } @@ -185,9 +176,9 @@ mod hw { && (layout.entry.page_count > 0) }) { let start = base + unsafe { layout.entry.rva as usize }; - let count = unsafe { layout.entry.page_count as usize }; + let size = unsafe { layout.entry.page_count as usize } << arch::SE_PAGE_SHIFT; - modify_perm(start, count, (arch::SI_FLAG_R | arch::SI_FLAG_W) as u8)?; + range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; } Ok(()) } @@ -230,27 +221,6 @@ mod hw { Ok(()) } - - fn modify_perm(addr: usize, count: usize, perm: u8) -> SgxResult { - let pages = PageRange::new( - addr, - count, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::PR | ProtFlags::from_bits_truncate(perm), - }, - )?; - - if SysFeatures::get().version() == Version::Sdk2_0 { - perm::modpr_ocall( - addr, - count, - ProtectPerm::try_from(perm).map_err(|_| SgxStatus::InvalidParameter)?, - )?; - } - - pages.modify() - } } #[cfg(any(feature = "sim", feature = "hyper"))] diff --git a/sgx_trts/src/edmm/tcs.rs b/sgx_trts/src/edmm/tcs.rs index e92d77be3..1a820fc13 100644 --- a/sgx_trts/src/edmm/tcs.rs +++ b/sgx_trts/src/edmm/tcs.rs @@ -63,7 +63,8 @@ pub fn mktcs(mk_tcs: NonNull) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] mod hw { use crate::arch::{self, Layout, Tcs}; - use crate::edmm::epc::{Page, PageInfo, PageType, ProtFlags}; + use crate::edmm::epc::PageType; + use crate::emm::range::{RangeType, RM}; use crate::enclave::MmLayout; use crate::tcs::list; use core::ptr; @@ -71,8 +72,7 @@ mod hw { use sgx_types::error::{SgxResult, SgxStatus}; pub fn add_tcs(mut tcs: NonNull) -> SgxResult { - use crate::call::{ocall, OCallIndex}; - use crate::edmm::{self, layout::LayoutTable}; + use crate::edmm::layout::LayoutTable; let base = MmLayout::image_base(); let table = LayoutTable::new(); @@ -93,8 +93,11 @@ mod hw { if let Some(layout) = table.layout_by_id(id) { if unsafe { layout.entry.attributes & arch::PAGE_ATTR_DYN_THREAD } != 0 { let addr = base + unsafe { layout.entry.rva as usize } + offset; - let count = unsafe { layout.entry.page_count }; - edmm::mem::apply_epc_pages(addr, count as usize)?; + let size = unsafe { layout.entry.page_count } << arch::SE_PAGE_SHIFT; + let mut range_manage = RM.get().unwrap().lock(); + range_manage + .commit(addr, size as usize, RangeType::Rts) + .map_err(|_| SgxStatus::Unexpected)?; } } } @@ -115,18 +118,15 @@ mod hw { tc.ofsbase = tcs_ptr + tc.ofsbase - base as u64; tc.ogsbase = tcs_ptr + tc.ogsbase - base as u64; - // ocall for MKTCS - ocall(OCallIndex::OCall(0), Some(tc))?; - - // EACCEPT for MKTCS - let page = Page::new( - tcs.as_ptr() as usize, - PageInfo { - typ: PageType::Tcs, - prot: ProtFlags::MODIFIED, - }, - )?; - page.accept()?; + let mut range_manage = RM.get().unwrap().lock(); + range_manage + .modify_type( + tcs.as_ptr() as usize, + arch::SE_PAGE_SIZE, + PageType::Tcs, + RangeType::Rts, + ) + .map_err(|_| SgxStatus::Unexpected)?; Ok(()) } @@ -167,23 +167,6 @@ mod hw { Ok(()) } } - - pub fn accept_trim_tcs(tcs: &Tcs) -> SgxResult { - let mut list_guard = list::TCS_LIST.lock(); - for tcs in list_guard.iter_mut().filter(|&t| !ptr::eq(t.as_ptr(), tcs)) { - let page = Page::new( - tcs.as_ptr() as usize, - PageInfo { - typ: PageType::Trim, - prot: ProtFlags::MODIFIED, - }, - )?; - page.accept()?; - } - - list_guard.clear(); - Ok(()) - } } #[cfg(any(feature = "sim", feature = "hyper"))] diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index 9eb6cbaec..6e2645621 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -19,7 +19,6 @@ use alloc::boxed::Box; use alloc::vec; use core::alloc::Allocator; use core::alloc::Layout; -use core::clone::Clone; use core::ptr::NonNull; use sgx_types::error::SgxResult; use sgx_types::error::SgxStatus; @@ -132,7 +131,7 @@ impl BitArray { let r_bits = self.bits - l_bits; let r_bytes = (r_bits + 7) / 8; - let r_array = Self::new(r_bits, self.alloc.clone())?; + let r_array = Self::new(r_bits, self.alloc)?; let r_data = unsafe { core::slice::from_raw_parts_mut(r_array.data, r_array.bytes) }; let l_data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index 3c489527c..d407067ca 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -15,29 +15,18 @@ // specific language governing permissions and limitations // under the License.. -use crate::arch::SE_PAGE_SHIFT; -use crate::arch::SE_PAGE_SIZE; -use crate::edmm::perm; -use crate::edmm::PageRange; -use crate::edmm::{PageInfo, PageType, ProtFlags}; +use crate::arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}; +use crate::edmm::{perm, PageInfo, PageRange, PageType, ProtFlags}; use crate::enclave::is_within_enclave; use alloc::boxed::Box; -use intrusive_collections::intrusive_adapter; -use intrusive_collections::LinkedListLink; -use intrusive_collections::UnsafeRef; -use sgx_types::error::SgxResult; -use sgx_types::error::SgxStatus; +use intrusive_collections::{intrusive_adapter, LinkedListLink, UnsafeRef}; +use sgx_types::error::{SgxResult, SgxStatus}; -use crate::feature::SysFeatures; -use crate::trts::Version; - -use super::alloc::ResAlloc; -use super::alloc::StaticAlloc; +use super::alloc::{ResAlloc, StaticAlloc}; use super::bitmap::BitArray; use super::flags::AllocFlags; use super::interior::Alloc; -use super::pfhandler::PfHandler; -use super::pfhandler::PfInfo; +use super::pfhandler::{PfHandler, PfInfo}; /// Enclave Management Area #[repr(C)] @@ -221,7 +210,7 @@ impl EMA { /// Check the prerequisites of ema commitment pub fn commit_check(&self) -> SgxResult { - if self.info.prot.intersects(ProtFlags::R | ProtFlags::W) { + if !self.info.prot.intersects(ProtFlags::R | ProtFlags::W) { return Err(SgxStatus::InvalidParameter); } @@ -410,17 +399,15 @@ impl EMA { } // Notify modifying permissions - if SysFeatures::get().version() == Version::Sdk2_0 { - perm::modify_ocall( - self.start, - self.length, - self.info, - PageInfo { - typ: self.info.typ, - prot: new_prot, - }, - )?; - } + perm::modify_ocall( + self.start, + self.length, + self.info, + PageInfo { + typ: self.info.typ, + prot: new_prot, + }, + )?; let info = PageInfo { typ: PageType::Reg, @@ -438,7 +425,6 @@ impl EMA { // If the new permission is RWX, no EMODPR needed in untrusted part (modify ocall) if (new_prot & (ProtFlags::W | ProtFlags::X)) != (ProtFlags::W | ProtFlags::X) { page.accept()?; - return Ok(()); } } @@ -447,7 +433,7 @@ impl EMA { prot: new_prot, }; - if new_prot == ProtFlags::NONE && SysFeatures::get().version() == Version::Sdk2_0 { + if new_prot == ProtFlags::NONE { perm::modify_ocall( self.start, self.length, @@ -578,7 +564,7 @@ impl EMA { pub fn set_eaccept_map_full(&mut self) -> SgxResult { if self.eaccept_map.is_none() { - let eaccept_map = match self.alloc { + let mut eaccept_map = match self.alloc { Alloc::Reserve => { let page_num = self.length >> SE_PAGE_SHIFT; BitArray::new(page_num, Alloc::Reserve)? @@ -588,6 +574,7 @@ impl EMA { BitArray::new(page_num, Alloc::Static)? } }; + eaccept_map.set_full(); self.eaccept_map = Some(eaccept_map); } else { self.eaccept_map.as_mut().unwrap().set_full(); @@ -605,7 +592,7 @@ impl EMA { /// Obtain the allocator of ema pub fn allocator(&self) -> Alloc { - self.alloc.clone() + self.alloc } pub fn flags(&self) -> AllocFlags { @@ -623,3 +610,24 @@ impl EMA { // Implement ema adapter for the operations of intrusive linkedlist intrusive_adapter!(pub EmaAda = UnsafeRef: EMA { link: LinkedListLink }); + +// pub struct EmaRange<'a> { +// pub cursor: CursorMut<'a, EmaAda>, +// pub count : usize, +// } + +// impl<'a> Iterator for EmaRange<'a> { +// type Item = &'a mut EMA; + +// fn next(&mut self) -> Option { +// if self.count == 0 { +// None +// } else { +// self.cursor.move_next(); +// self.count -= 1; + +// let ema = unsafe { self.cursor.get_mut().unwrap() }; +// Some(ema) +// } +// } +// } diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs index 37b3094ea..24eaf2348 100644 --- a/sgx_trts/src/emm/init.rs +++ b/sgx_trts/src/emm/init.rs @@ -26,18 +26,23 @@ use crate::emm::range::{RangeType, EMA_PROT_MASK}; use crate::enclave::MmLayout; use crate::{arch, emm::range::RM}; -use super::{interior::init_alloc, range::init_range_manage, user::init_user_range}; +use super::interior::{init_reserve_alloc, init_static_alloc}; +use super::range::init_range_manage; -pub fn init_emm(user_start: usize, user_end: usize) { - // check user_start not equals to 0 - init_user_range(user_start, user_end); +pub fn init_emm() { init_range_manage(); - init_alloc(); + init_static_alloc(); + init_reserve_alloc(); } pub fn init_rts_emas() -> SgxResult { init_segment_emas()?; - init_rts_contexts_emas(arch::Global::get().layout_table(), 0)?; + // let mut layout = arch::Global::get().layout_table(); + // layout = &layout[..(layout.len() - 1)]; + + // let layout = arch::Global::get().layout_table().split_last().unwrap().1; + let layout = arch::Global::get().layout_table(); + init_rts_contexts_emas(layout, 0)?; Ok(()) } @@ -59,11 +64,15 @@ fn init_rts_contexts_emas(table: &[Layout], offset: usize) -> SgxResult { } fn build_rts_context_emas(entry: &LayoutEntry, offset: usize) -> SgxResult { + if entry.id == arch::LAYOUT_ID_USER_REGION { + return Ok(()); + } + let rva = offset + (entry.rva as usize); assert!(is_page_aligned!(rva)); // TODO: not sure get_enclave_base() equal to elrange_base or image_base - let addr = MmLayout::image_base() + (rva as usize); + let addr = MmLayout::image_base() + rva; let size = (entry.page_count << arch::SE_PAGE_SHIFT) as usize; let mut range_manage = RM.get().unwrap().lock(); @@ -85,7 +94,7 @@ fn build_rts_context_emas(entry: &LayoutEntry, offset: usize) -> SgxResult { let post_remove = (entry.attributes & arch::PAGE_ATTR_POST_REMOVE) != 0; let post_add = (entry.attributes & arch::PAGE_ATTR_POST_ADD) != 0; - let static_min = (entry.attributes & arch::PAGE_ATTR_EADD) != 0; + let static_min = ((entry.attributes & arch::PAGE_ATTR_EADD) != 0) && !post_remove; if post_remove { // TODO: maybe AllocFlags need more flags or PageType is not None diff --git a/sgx_trts/src/emm/interior.rs b/sgx_trts/src/emm/interior.rs index d0c111e8f..6dfc21f53 100644 --- a/sgx_trts/src/emm/interior.rs +++ b/sgx_trts/src/emm/interior.rs @@ -45,12 +45,6 @@ const MAX_EMALLOC_SIZE: usize = 0x10000000; const ALLOC_MASK: usize = 1; const SIZE_MASK: usize = !(EXACT_MATCH_INCREMENT - 1); -/// Init two level allocator -pub fn init_alloc() { - init_static_alloc(); - init_reserve_alloc() -} - /// Lowest level: Allocator for static memory pub static STATIC: Once> = Once::new(); @@ -58,7 +52,7 @@ pub static STATIC: Once> = Once::new(); static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; /// Init lowest level static memory allocator -fn init_static_alloc() { +pub fn init_static_alloc() { STATIC.call_once(|| { let static_alloc = LockedHeap::empty(); unsafe { @@ -75,12 +69,12 @@ pub static RES_ALLOCATOR: Once> = Once::new(); /// Init reserve memory allocator /// init_reserve_alloc() need to be called after init_static_alloc() -fn init_reserve_alloc() { +pub fn init_reserve_alloc() { RES_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); } // Enum for allocator types -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum Alloc { Static, diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index e185bc2bf..99857b64c 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -18,7 +18,7 @@ use crate::{ arch::SE_PAGE_SIZE, edmm::{PageInfo, PageType, ProtFlags}, - enclave::is_within_enclave, + enclave::{is_within_enclave, MmLayout}, sync::SpinReentrantMutex, }; use alloc::boxed::Box; @@ -32,7 +32,7 @@ use super::{ flags::AllocFlags, interior::Alloc, pfhandler::{PfHandler, PfInfo}, - user::{is_within_rts_range, is_within_user_range, USER_RANGE}, + user::{is_within_rts_range, is_within_user_range}, }; const ALLOC_FLAGS_SHIFT: usize = 0; @@ -116,6 +116,44 @@ impl RangeManage { Ok(()) } + // Clear the EMAs in charging of [start, end) memory region, + // return next ema cursor + fn clear_reserved_emas( + &mut self, + start: usize, + end: usize, + typ: RangeType, + alloc: Alloc, + ) -> SgxResult> { + let (mut cursor, ema_num) = self.search_ema_range(start, end, typ, true)?; + let start_ema_ptr = cursor.get().unwrap() as *const EMA; + + // Check EMA attributes + let mut count = ema_num; + while count != 0 { + let ema = cursor.get().unwrap(); + // EMA must be reserved and can not manage internal memory region + if !ema.flags().contains(AllocFlags::RESERVED) || ema.allocator() != alloc { + return Err(SgxStatus::InvalidParameter); + } + cursor.move_next(); + count -= 1; + } + + let mut cursor = match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, + }; + + count = ema_num; + while count != 0 { + cursor.remove(); + count -= 1; + } + + Ok(cursor) + } + /// Allocate a new memory region in enclave address space (ELRANGE). pub fn alloc( &mut self, @@ -183,6 +221,9 @@ impl RangeManage { } }; + let mut alloc_addr: Option = None; + let mut alloc_next_ema: Option> = None; + if addr > 0 { let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); // FIXME: search_ema_range implicitly contains splitting ema! @@ -192,8 +233,16 @@ impl RangeManage { // exist in emas list Ok(_) => { // TODO: realloc EMA from reserve - if is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); + match self.clear_reserved_emas(addr, addr + size, typ, alloc) { + Ok(ema) => { + alloc_addr = Some(addr); + alloc_next_ema = Some(ema); + } + Err(_) => { + if is_fixed_alloc { + return Err(SgxStatus::InvalidParameter); + } + } } } // not exist in emas list @@ -206,13 +255,19 @@ impl RangeManage { }; }; - let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; + if alloc_addr.is_none() { + let (free_addr, next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; + alloc_addr = Some(free_addr); + alloc_next_ema = Some(next_ema); + } + + // let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; let new_ema_ref = match alloc { Alloc::Reserve => { let mut new_ema = Box::::new_in( EMA::new( - free_addr, + alloc_addr.unwrap(), size, alloc_flags, info, @@ -229,7 +284,7 @@ impl RangeManage { Alloc::Static => { let mut new_ema = Box::::new_in( EMA::new( - free_addr, + alloc_addr.unwrap(), size, alloc_flags, info, @@ -245,8 +300,8 @@ impl RangeManage { } }; - next_ema.insert_before(new_ema_ref); - Ok(free_addr) + alloc_next_ema.unwrap().insert_before(new_ema_ref); + Ok(alloc_addr.unwrap()) } /// Allocate a new memory region in enclave address space (ELRANGE). @@ -279,6 +334,9 @@ impl RangeManage { return Err(SgxStatus::InvalidParameter); } + let mut alloc_addr: Option = None; + let mut alloc_next_ema: Option> = None; + if addr > 0 { let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); // FIXME: search_ema_range implicitly contains splitting ema! @@ -288,8 +346,16 @@ impl RangeManage { // exist in emas list Ok(_) => { // TODO: realloc EMA from reserve - if is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); + match self.clear_reserved_emas(addr, addr + size, typ, alloc) { + Ok(ema) => { + alloc_addr = Some(addr); + alloc_next_ema = Some(ema); + } + Err(_) => { + if is_fixed_alloc { + return Err(SgxStatus::InvalidParameter); + } + } } } // not exist in emas list @@ -302,13 +368,19 @@ impl RangeManage { }; }; - let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; + if alloc_addr.is_none() { + let (free_addr, next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; + alloc_addr = Some(free_addr); + alloc_next_ema = Some(next_ema); + } + + // let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; let new_ema_ref = match alloc { Alloc::Reserve => { let mut new_ema = Box::::new_in( EMA::new( - free_addr, + alloc_addr.unwrap(), size, alloc_flags, info, @@ -325,7 +397,7 @@ impl RangeManage { Alloc::Static => { let mut new_ema = Box::::new_in( EMA::new( - free_addr, + alloc_addr.unwrap(), size, alloc_flags, info, @@ -341,8 +413,8 @@ impl RangeManage { } }; - next_ema.insert_before(new_ema_ref); - Ok(free_addr) + alloc_next_ema.unwrap().insert_before(new_ema_ref); + Ok(alloc_addr.unwrap()) } /// Commit a partial or full range of memory allocated previously with @@ -428,18 +500,22 @@ impl RangeManage { typ: RangeType, ) -> SgxResult { ensure!( - (size != 0) - && (size % SE_PAGE_SIZE == 0) - && (addr % SE_PAGE_SIZE == 0) - && (prot.contains(ProtFlags::X) && !prot.contains(ProtFlags::R)), + (size != 0) && (size % SE_PAGE_SIZE == 0) && (addr % SE_PAGE_SIZE == 0), SgxStatus::InvalidParameter ); + + if prot.contains(ProtFlags::X) && !prot.contains(ProtFlags::R) { + return Err(SgxStatus::InvalidParameter); + } + let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; let mut count = ema_num; while count != 0 { - cursor.get().unwrap().modify_perm_check()?; + let ema = cursor.get().unwrap(); + ema.modify_perm_check()?; + // cursor.get().unwrap().modify_perm_check()?; cursor.move_next(); count -= 1; } @@ -659,9 +735,8 @@ impl RangeManage { align: usize, typ: RangeType, ) -> SgxResult<(usize, CursorMut<'_, EmaAda>)> { - let user_range = USER_RANGE.get().unwrap(); - let user_base = user_range.start; - let user_end = user_range.end; + let user_base = MmLayout::user_region_mem_base(); + let user_end = user_base + MmLayout::user_region_mem_size(); let mut addr; diff --git a/sgx_trts/src/emm/user.rs b/sgx_trts/src/emm/user.rs index 85baaff40..c65a40716 100644 --- a/sgx_trts/src/emm/user.rs +++ b/sgx_trts/src/emm/user.rs @@ -15,30 +15,7 @@ // specific language governing permissions and limitations // under the License.. -use spin::Once; - -#[derive(Clone, Copy)] -pub struct UserRange { - pub start: usize, - pub end: usize, -} - -impl UserRange { - fn start(&self) -> usize { - self.start - } - fn end(&self) -> usize { - self.end - } -} - -/// User memory range specified by SDK developer -pub static USER_RANGE: Once = Once::new(); - -pub fn init_user_range(start: usize, end: usize) { - let _ = *USER_RANGE.call_once(|| UserRange { start, end }); -} - +use crate::enclave::MmLayout; pub fn is_within_rts_range(start: usize, len: usize) -> bool { let end = if len > 0 { if let Some(end) = start.checked_add(len - 1) { @@ -49,11 +26,11 @@ pub fn is_within_rts_range(start: usize, len: usize) -> bool { } else { start }; - let user_range = USER_RANGE.get().unwrap(); - let user_start = user_range.start(); - let user_end = user_range.end(); - (start >= user_end) || (end < user_start) + let user_base = MmLayout::user_region_mem_base(); + let user_end = user_base + MmLayout::user_region_mem_size(); + + (start <= end) && ((start >= user_end) || (end < user_base)) } pub fn is_within_user_range(start: usize, len: usize) -> bool { @@ -66,9 +43,9 @@ pub fn is_within_user_range(start: usize, len: usize) -> bool { } else { start }; - let user_range = USER_RANGE.get().unwrap(); - let user_start = user_range.start(); - let user_end = user_range.end(); - (start <= end) && (start >= user_start) && (end < user_end) + let user_base = MmLayout::user_region_mem_base(); + let user_end = user_base + MmLayout::user_region_mem_size(); + + (start <= end) && (start >= user_base) && (end < user_end) } diff --git a/sgx_trts/src/enclave/init.rs b/sgx_trts/src/enclave/init.rs index 0ee5333fe..c805a63a9 100644 --- a/sgx_trts/src/enclave/init.rs +++ b/sgx_trts/src/enclave/init.rs @@ -81,15 +81,6 @@ pub fn rtinit(tcs: &mut Tcs, ms: *mut SystemFeatures, tidx: usize) -> SgxResult tc::ThreadControl::from_tcs(tcs).init(tidx, true)?; - // #[cfg(not(any(feature = "sim", feature = "hyper")))] - // { - // if features.is_edmm() { - // // EDMM: - // // need to accept the trimming of the POST_REMOVE pages - // crate::edmm::mem::accept_post_remove()?; - // } - // } - heap.zero_memory(); rsrvmem.zero_memory(); @@ -99,7 +90,8 @@ pub fn rtinit(tcs: &mut Tcs, ms: *mut SystemFeatures, tidx: usize) -> SgxResult { if features.is_edmm() { let usermem = mem::UserRegionMem::get_or_init(); - init_emm(usermem.base, usermem.base + usermem.size); + init_emm(); + init_rts_emas()?; } } diff --git a/sgx_trts/src/enclave/uninit.rs b/sgx_trts/src/enclave/uninit.rs index 78a79dcb8..634a4832e 100644 --- a/sgx_trts/src/enclave/uninit.rs +++ b/sgx_trts/src/enclave/uninit.rs @@ -15,9 +15,11 @@ // specific language governing permissions and limitations // under the License.. +use crate::arch; +use crate::emm::range::{RangeType, RM}; use crate::enclave::state::{self, State}; use crate::enclave::{atexit, parse}; -use crate::tcs::ThreadControl; +use crate::tcs::{list, ThreadControl}; use core::sync::atomic::AtomicBool; use sgx_types::error::SgxResult; @@ -61,7 +63,7 @@ pub fn rtuninit(tc: ThreadControl) -> SgxResult { let is_legal = tc.is_init(); } else { use crate::feature::SysFeatures; - use crate::edmm::{self, layout::LayoutTable}; + use crate::edmm::layout::LayoutTable; let is_legal = if SysFeatures::get().is_edmm() { tc.is_utility() || !LayoutTable::new().is_dyn_tcs_exist() @@ -79,9 +81,24 @@ pub fn rtuninit(tc: ThreadControl) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] { - if SysFeatures::get().is_edmm() && edmm::tcs::accept_trim_tcs(tcs).is_err() { - state::set_state(State::Crashed); - bail!(SgxStatus::Unexpected); + // if SysFeatures::get().is_edmm() && edmm::tcs::accept_trim_tcs(tcs).is_err() { + // state::set_state(State::Crashed); + // bail!(SgxStatus::Unexpected); + // } + if SysFeatures::get().is_edmm() { + let mut range_manage = RM.get().unwrap().lock(); + + let mut list_guard = list::TCS_LIST.lock(); + for tcs in list_guard.iter_mut().filter(|&t| !ptr::eq(t.as_ptr(), tcs)) { + let result = + range_manage.dealloc(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE, RangeType::Rts); + if result.is_err() { + state::set_state(State::Crashed); + bail!(SgxStatus::Unexpected); + } + } + + list_guard.clear(); } } diff --git a/sgx_trts/src/tcs/tc.rs b/sgx_trts/src/tcs/tc.rs index 629426e7a..ecad2020d 100644 --- a/sgx_trts/src/tcs/tc.rs +++ b/sgx_trts/src/tcs/tc.rs @@ -30,7 +30,7 @@ use sgx_types::error::SgxResult; #[link_section = ".data.rel.ro"] static mut STACK_CHK_GUARD: OnceCell = OnceCell::new(); -pub const STATIC_STACK_SIZE: usize = 2656; // 16 bytes aligned +pub const STATIC_STACK_SIZE: usize = 4096; const CANARY_OFFSET: usize = arch::SE_GUARD_PAGE_SIZE + STATIC_STACK_SIZE - mem::size_of::(); extern "C" { From 329ceb569696b014453b737007d24cf24aa4bc39 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 15 Sep 2023 18:19:39 +0800 Subject: [PATCH 08/20] Reconstruct emm and sdk code --- sgx_rsrvmm/src/rsrvmm/area.rs | 4 +- sgx_rsrvmm/src/rsrvmm/mod.rs | 4 +- sgx_trts/src/arch.rs | 2 +- sgx_trts/src/call/ecall.rs | 6 +- sgx_trts/src/capi.rs | 147 +++++- sgx_trts/src/edmm/mem.rs | 247 ---------- sgx_trts/src/edmm/mod.rs | 29 -- sgx_trts/src/emm/alloc.rs | 474 ++++++++++++++++++- sgx_trts/src/emm/bitmap.rs | 2 +- sgx_trts/src/emm/ema.rs | 19 +- sgx_trts/src/emm/flags.rs | 30 -- sgx_trts/src/emm/init.rs | 352 +++++++++----- sgx_trts/src/emm/interior.rs | 482 -------------------- sgx_trts/src/{edmm => emm}/layout.rs | 0 sgx_trts/src/emm/mod.rs | 12 +- sgx_trts/src/{edmm/perm.rs => emm/ocall.rs} | 107 +++-- sgx_trts/src/{edmm/epc.rs => emm/page.rs} | 65 ++- sgx_trts/src/emm/pfhandler.rs | 4 +- sgx_trts/src/emm/range.rs | 201 +------- sgx_trts/src/{edmm => emm}/tcs.rs | 4 +- sgx_trts/src/{edmm => emm}/trim.rs | 0 sgx_trts/src/emm/user.rs | 51 --- sgx_trts/src/enclave/entry.rs | 4 +- sgx_trts/src/enclave/mem.rs | 34 ++ sgx_trts/src/enclave/mod.rs | 5 +- sgx_trts/src/enclave/uninit.rs | 6 +- sgx_trts/src/lib.rs | 1 - sgx_trts/src/tcs/tc.rs | 4 +- sgx_trts/src/veh/exception.rs | 4 +- 29 files changed, 1051 insertions(+), 1249 deletions(-) delete mode 100644 sgx_trts/src/edmm/mem.rs delete mode 100644 sgx_trts/src/edmm/mod.rs delete mode 100644 sgx_trts/src/emm/flags.rs delete mode 100644 sgx_trts/src/emm/interior.rs rename sgx_trts/src/{edmm => emm}/layout.rs (100%) rename sgx_trts/src/{edmm/perm.rs => emm/ocall.rs} (88%) rename sgx_trts/src/{edmm/epc.rs => emm/page.rs} (77%) rename sgx_trts/src/{edmm => emm}/tcs.rs (98%) rename sgx_trts/src/{edmm => emm}/trim.rs (100%) delete mode 100644 sgx_trts/src/emm/user.rs diff --git a/sgx_rsrvmm/src/rsrvmm/area.rs b/sgx_rsrvmm/src/rsrvmm/area.rs index 10840043a..105dea920 100644 --- a/sgx_rsrvmm/src/rsrvmm/area.rs +++ b/sgx_rsrvmm/src/rsrvmm/area.rs @@ -24,8 +24,8 @@ use core::cmp::{self, Ordering}; use core::convert::From; use core::fmt; use core::ops::{Deref, DerefMut}; -use sgx_trts::edmm::{modpr_ocall, mprotect_ocall}; -use sgx_trts::edmm::{ProtFlags, PageInfo, PageRange, PageType}; +use sgx_trts::emm::{modpr_ocall, mprotect_ocall}; +use sgx_trts::emm::{ProtFlags, PageInfo, PageRange, PageType}; use sgx_trts::trts; use sgx_types::error::errno::*; use sgx_types::error::OsResult; diff --git a/sgx_rsrvmm/src/rsrvmm/mod.rs b/sgx_rsrvmm/src/rsrvmm/mod.rs index dbae758ac..e4299c94f 100644 --- a/sgx_rsrvmm/src/rsrvmm/mod.rs +++ b/sgx_rsrvmm/src/rsrvmm/mod.rs @@ -20,7 +20,7 @@ use self::manager::{MmAllocAddr, MmManager}; use self::range::MmRange; use crate::map::{Map, MapObject}; use sgx_sync::{Once, StaticMutex}; -use sgx_trts::edmm; +use sgx_trts::emm; use sgx_trts::trts::{self, MmLayout}; use sgx_types::error::errno::*; use sgx_types::error::OsResult; @@ -161,7 +161,7 @@ impl RsrvMem { ) }; - let ret = edmm::apply_epc_pages(start_addr, size >> SE_PAGE_SHIFT); + let ret = emm::apply_epc_pages(start_addr, size >> SE_PAGE_SHIFT); if ret.is_err() { self.committed_size = pre_committed; bail!(ENOMEM); diff --git a/sgx_trts/src/arch.rs b/sgx_trts/src/arch.rs index 68b439ec0..567136c32 100644 --- a/sgx_trts/src/arch.rs +++ b/sgx_trts/src/arch.rs @@ -17,7 +17,7 @@ #![allow(clippy::enum_variant_names)] -use crate::edmm::{self, PageType}; +use crate::emm::{PageInfo, PageType}; use crate::tcs::tc; use crate::version::*; use crate::xsave; diff --git a/sgx_trts/src/call/ecall.rs b/sgx_trts/src/call/ecall.rs index 05b8f88ce..02d90d68c 100644 --- a/sgx_trts/src/call/ecall.rs +++ b/sgx_trts/src/call/ecall.rs @@ -278,11 +278,11 @@ pub fn ecall(idx: ECallIndex, tcs: &mut Tcs, ms: *mut T, tidx: usize) -> SgxR { if crate::feature::SysFeatures::get().is_edmm() { // save all the static tcs into the tcs table. These TCS would be trimmed in the uninit flow. - crate::edmm::tcs::add_static_tcs()?; + crate::emm::tcs::add_static_tcs()?; // change back the page permission - crate::edmm::mem::change_perm().map_err(|e| { - let _ = crate::edmm::tcs::clear_static_tcs(); + crate::emm::init::change_perm().map_err(|e| { + let _ = crate::emm::tcs::clear_static_tcs(); e })?; } diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs index 9cf01743f..2855b2e53 100644 --- a/sgx_trts/src/capi.rs +++ b/sgx_trts/src/capi.rs @@ -15,9 +15,17 @@ // specific language governing permissions and limitations // under the License.. +use crate::arch::SE_PAGE_SIZE; use crate::call::{ocall, OCallIndex, OcBuffer}; -use crate::edmm::mem::{apply_epc_pages, trim_epc_pages}; -use crate::enclave::{self, MmLayout}; +use crate::emm::alloc::Alloc; +use crate::emm::page::AllocFlags; +use crate::emm::pfhandler::{PfHandler, PfInfo}; +use crate::emm::range::{ + RangeType, ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, + PAGE_TYPE_MASK, PAGE_TYPE_SHIFT, RM, +}; +use crate::emm::{apply_epc_pages, trim_epc_pages, PageInfo, PageType, ProtFlags}; +use crate::enclave::{self, is_within_enclave, MmLayout}; use crate::error; use crate::rand::rand; use crate::tcs::{current, stack_size, tcs_max_num, tcs_policy}; @@ -26,8 +34,8 @@ use crate::veh::{register_exception, unregister, ExceptionHandler, Handle}; use core::convert::TryFrom; use core::ffi::c_void; use core::num::NonZeroUsize; -use core::ptr; use core::slice; +use core::{mem, ptr}; use sgx_types::error::SgxStatus; #[inline] @@ -170,6 +178,119 @@ pub unsafe extern "C" fn sgx_is_outside_enclave(p: *const u8, len: usize) -> i32 i32::from(enclave::is_within_host(p, len)) } +#[inline] +#[no_mangle] +pub unsafe extern "C" fn sgx_apply_epc_pages(addr: usize, count: usize) -> i32 { + if apply_epc_pages(addr, count).is_ok() { + 0 + } else { + -1 + } +} + +#[inline] +#[no_mangle] +pub unsafe extern "C" fn sgx_trim_epc_pages(addr: usize, count: usize) -> i32 { + if trim_epc_pages(addr, count).is_ok() { + 0 + } else { + -1 + } +} + +// TODO: replace inarguments with "C" style arguments +#[inline] +#[no_mangle] +pub unsafe extern "C" fn sgx_mm_alloc( + addr: usize, + size: usize, + flags: usize, + handler: *mut c_void, + priv_data: *mut PfInfo, + out_addr: *mut *mut u8, +) -> u32 { + let handler = if handler.is_null() { + None + } else { + Some(mem::transmute::<*mut c_void, PfHandler>(handler)) + }; + + let alloc_flags = + match AllocFlags::from_bits(((flags & ALLOC_FLAGS_MASK) >> ALLOC_FLAGS_SHIFT) as u32) { + Some(flags) => flags, + None => { + return SgxStatus::InvalidParameter.into(); + } + }; + + let mut page_type = + match PageType::try_from(((flags & PAGE_TYPE_MASK) >> PAGE_TYPE_SHIFT) as u8) { + Ok(typ) => typ, + Err(_) => return SgxStatus::InvalidParameter.into(), + }; + + if page_type == PageType::None { + page_type = PageType::Reg; + } + + if (size % SE_PAGE_SIZE) > 0 { + return SgxStatus::InvalidParameter.into(); + } + + let mut align_flag: u8 = ((flags & ALLIGNMENT_MASK) >> ALLIGNMENT_SHIFT) as u8; + if align_flag == 0 { + align_flag = 12; + } + if align_flag < 12 { + return SgxStatus::InvalidParameter.into(); + } + let align_mask: usize = (1 << align_flag) - 1; + + if (addr & align_mask) > 0 { + return SgxStatus::InvalidParameter.into(); + } + + if (addr > 0) && !is_within_enclave(addr as *const u8, size) { + return SgxStatus::InvalidParameter.into(); + } + + let info = if alloc_flags.contains(AllocFlags::RESERVED) { + PageInfo { + prot: ProtFlags::NONE, + typ: PageType::None, + } + } else { + PageInfo { + prot: ProtFlags::R | ProtFlags::W, + typ: page_type, + } + }; + + let priv_data = if priv_data.is_null() { + None + } else { + Some(priv_data) + }; + + let mut range_manage = RM.get().unwrap().lock(); + match range_manage.alloc( + Some(addr), + size, + alloc_flags, + info, + handler, + priv_data, + RangeType::User, + Alloc::Reserve, + ) { + Ok(base) => { + *out_addr = base as *mut u8; + 0 + } + Err(err) => err.into(), + } +} + #[inline] #[no_mangle] pub unsafe extern "C" fn sgx_ocall(idx: i32, ms: *mut c_void) -> u32 { @@ -226,26 +347,6 @@ pub unsafe extern "C" fn sgx_ocremain_size() -> usize { OcBuffer::remain_size() } -#[inline] -#[no_mangle] -pub unsafe extern "C" fn sgx_apply_epc_pages(addr: usize, count: usize) -> i32 { - if apply_epc_pages(addr, count).is_ok() { - 0 - } else { - -1 - } -} - -#[inline] -#[no_mangle] -pub unsafe extern "C" fn sgx_trim_epc_pages(addr: usize, count: usize) -> i32 { - if trim_epc_pages(addr, count).is_ok() { - 0 - } else { - -1 - } -} - #[allow(clippy::redundant_closure)] #[inline] #[no_mangle] diff --git a/sgx_trts/src/edmm/mem.rs b/sgx_trts/src/edmm/mem.rs deleted file mode 100644 index e32256f84..000000000 --- a/sgx_trts/src/edmm/mem.rs +++ /dev/null @@ -1,247 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License.. - -cfg_if! { - if #[cfg(not(any(feature = "sim", feature = "hyper")))] { - pub use hw::*; - } else { - pub use sw::*; - } -} - -#[cfg(not(any(feature = "sim", feature = "hyper")))] -mod hw { - use crate::arch::{self, Layout}; - use crate::edmm::epc::{PageInfo, PageRange, PageType, ProtFlags}; - use crate::edmm::layout::LayoutTable; - use crate::edmm::trim; - use crate::elf::program::Type; - use crate::emm::flags::AllocFlags; - use crate::emm::range::{RangeType, RM}; - use crate::enclave::parse; - use crate::enclave::MmLayout; - use sgx_types::error::{SgxResult, SgxStatus}; - - pub fn apply_epc_pages(addr: usize, count: usize) -> SgxResult { - ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); - - if let Some(attr) = LayoutTable::new().check_dyn_range(addr, count, None) { - let pages = PageRange::new( - addr, - count, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, - }, - )?; - if (attr.attr & arch::PAGE_DIR_GROW_DOWN) == 0 { - pages.accept_forward() - } else { - pages.accept_backward() - } - } else { - Err(SgxStatus::InvalidParameter) - } - } - - pub fn trim_epc_pages(addr: usize, count: usize) -> SgxResult { - ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); - - LayoutTable::new() - .check_dyn_range(addr, count, None) - .ok_or(SgxStatus::InvalidParameter)?; - - trim::trim_range(addr, count)?; - - let pages = PageRange::new( - addr, - count, - PageInfo { - typ: PageType::Trim, - prot: ProtFlags::MODIFIED, - }, - )?; - pages.accept_forward()?; - - trim::trim_range_commit(addr, count)?; - - Ok(()) - } - - pub fn expand_stack_epc_pages(addr: usize, count: usize) -> SgxResult { - ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); - - LayoutTable::new() - .check_dyn_range(addr, count, None) - .ok_or(SgxStatus::InvalidParameter)?; - - let mut range_manage = RM.get().unwrap().lock(); - range_manage.commit(addr, count << arch::SE_PAGE_SHIFT, RangeType::Rts)?; - - Ok(()) - } - - #[inline] - pub fn accept_post_remove() -> SgxResult { - reentrant_accept_post_remove(arch::Global::get().layout_table(), 0) - } - - fn reentrant_accept_post_remove(table: &[Layout], offset: usize) -> SgxResult { - let base = MmLayout::image_base(); - unsafe { - for (i, layout) in table.iter().enumerate() { - if is_group_id!(layout.group.id) { - let mut step = 0_usize; - for _ in 0..layout.group.load_times { - step += layout.group.load_step as usize; - reentrant_accept_post_remove( - &table[i - layout.group.entry_count as usize..i], - step, - )?; - } - } else if (layout.entry.attributes & arch::PAGE_ATTR_POST_REMOVE) != 0 { - let addr = base + layout.entry.rva as usize + offset; - let count = layout.entry.page_count as usize; - - let pages = PageRange::new( - addr, - count, - PageInfo { - typ: PageType::Trim, - prot: ProtFlags::MODIFIED, - }, - )?; - pages.accept_forward()?; - } - } - Ok(()) - } - } - - pub fn change_perm() -> SgxResult { - let elf = parse::new_elf()?; - let text_relo = parse::has_text_relo()?; - - let base = MmLayout::image_base(); - let mut range_manage = RM.get().unwrap().lock(); - for phdr in elf.program_iter() { - let typ = phdr.get_type().unwrap_or(Type::Null); - if typ == Type::Load && text_relo && !phdr.flags().is_write() { - let mut perm = 0_u64; - let start = base + trim_to_page!(phdr.virtual_addr() as usize); - let end = - base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); - let size = end - start; - - if phdr.flags().is_read() { - perm |= arch::SGX_EMA_PROT_READ; - } - if phdr.flags().is_execute() { - perm |= arch::SGX_EMA_PROT_EXEC; - } - - let prot = ProtFlags::from_bits_truncate(perm as u8); - range_manage.modify_perms(start, size, prot, RangeType::Rts)?; - } - if typ == Type::GnuRelro { - let start = base + trim_to_page!(phdr.virtual_addr() as usize); - let end = - base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); - let size = end - start; - - if size > 0 { - range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; - } - } - } - - let layout_table = arch::Global::get().layout_table(); - if let Some(layout) = layout_table.iter().find(|layout| unsafe { - (layout.entry.id == arch::LAYOUT_ID_RSRV_MIN) - && (layout.entry.si_flags == arch::SI_FLAGS_RWX) - && (layout.entry.page_count > 0) - }) { - let start = base + unsafe { layout.entry.rva as usize }; - let size = unsafe { layout.entry.page_count as usize } << arch::SE_PAGE_SHIFT; - - range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; - } - Ok(()) - } - - pub fn init_segment_emas() -> SgxResult { - let elf = parse::new_elf()?; - let text_relo = parse::has_text_relo()?; - - let base = MmLayout::image_base(); - for phdr in elf.program_iter() { - let typ = phdr.get_type().unwrap_or(Type::Null); - - if typ == Type::Load { - let mut perm = ProtFlags::R; - let start = base + trim_to_page!(phdr.virtual_addr() as usize); - let end = - base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); - - if phdr.flags().is_write() || text_relo { - perm |= ProtFlags::W; - } - if phdr.flags().is_execute() { - perm |= ProtFlags::X; - } - - let mut range_manage = RM.get().unwrap().lock(); - range_manage.init_static_region( - start, - end - start, - AllocFlags::SYSTEM, - PageInfo { - typ: PageType::Reg, - prot: perm, - }, - None, - None, - )?; - } - } - - Ok(()) - } -} - -#[cfg(any(feature = "sim", feature = "hyper"))] -mod sw { - use sgx_types::error::SgxResult; - - #[allow(clippy::unnecessary_wraps)] - #[inline] - pub fn apply_epc_pages(_addr: usize, _count: usize) -> SgxResult { - Ok(()) - } - - #[allow(clippy::unnecessary_wraps)] - #[inline] - pub fn trim_epc_pages(_addr: usize, _count: usize) -> SgxResult { - Ok(()) - } - - #[allow(clippy::unnecessary_wraps)] - #[inline] - pub fn expand_stack_epc_pages(_addr: usize, _count: usize) -> SgxResult { - Ok(()) - } -} diff --git a/sgx_trts/src/edmm/mod.rs b/sgx_trts/src/edmm/mod.rs deleted file mode 100644 index c54b036b0..000000000 --- a/sgx_trts/src/edmm/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License.. - -pub(crate) mod epc; -#[cfg(not(any(feature = "sim", feature = "hyper")))] -pub(crate) mod layout; -pub(crate) mod mem; -pub(crate) mod perm; -pub(crate) mod tcs; -#[cfg(not(any(feature = "sim", feature = "hyper")))] -pub(crate) mod trim; - -pub use epc::{PageInfo, PageRange, PageType, ProtFlags}; -pub use mem::{apply_epc_pages, trim_epc_pages}; -pub use perm::{modpr_ocall, mprotect_ocall}; diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index dee4a9c39..b54533ed4 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -15,10 +15,66 @@ // specific language governing permissions and limitations // under the License.. +use buddy_system_allocator::LockedHeap; +use intrusive_collections::intrusive_adapter; +use intrusive_collections::singly_linked_list::CursorMut; +use intrusive_collections::singly_linked_list::{Link, SinglyLinkedList}; +use intrusive_collections::UnsafeRef; + use core::alloc::{AllocError, Allocator, Layout}; +use core::mem::size_of; +use core::mem::transmute; +use core::mem::MaybeUninit; use core::ptr::NonNull; +use spin::{Mutex, Once}; + +use super::page::AllocFlags; +use super::range::{RangeType, RM}; +use super::{PageInfo, PageType, ProtFlags}; +use sgx_types::error::{SgxResult, SgxStatus}; + +// The size of fixed static memory for Static Allocator +const STATIC_MEM_SIZE: usize = 65536; + +// The size of initial reserve memory for Reserve Allocator +const INIT_MEM_SIZE: usize = 65536; + +// The size of guard pages +const GUARD_SIZE: usize = 0x8000; + +// The max allocated size of Reserve Allocator +const MAX_EMALLOC_SIZE: usize = 0x10000000; + +const ALLOC_MASK: usize = 1; +const SIZE_MASK: usize = !(EXACT_MATCH_INCREMENT - 1); -use crate::emm::interior::{RES_ALLOCATOR, STATIC}; +/// Lowest level: Allocator for static memory +pub static STATIC: Once> = Once::new(); + +/// Static memory for allocation +static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; + +/// Init lowest level static memory allocator +pub fn init_static_alloc() { + STATIC.call_once(|| { + let static_alloc = LockedHeap::empty(); + unsafe { + static_alloc + .lock() + .init(STATIC_MEM.as_ptr() as usize, STATIC_MEM_SIZE) + }; + static_alloc + }); +} + +/// Second level: Allocator for reserve memory +pub static RES_ALLOCATOR: Once> = Once::new(); + +/// Init reserve memory allocator +/// init_reserve_alloc() need to be called after init_static_alloc() +pub fn init_reserve_alloc() { + RES_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); +} /// Alloc layout memory from reserve memory region #[derive(Clone, Copy)] @@ -62,3 +118,419 @@ unsafe impl Allocator for StaticAlloc { STATIC.get().unwrap().lock().dealloc(ptr, layout); } } + +// Enum for allocator types +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum Alloc { + Static, + Reserve, +} + +// Chunk manages memory range. +// The Chunk structure is filled into the layout before the base pointer. +#[derive(Debug)] +struct Chunk { + base: usize, + size: usize, + used: usize, + link: Link, // singly intrusive linkedlist +} + +impl Chunk { + fn new(base: usize, size: usize) -> Self { + Self { + base, + size, + used: 0, + link: Link::new(), + } + } +} + +intrusive_adapter!(ChunkAda = UnsafeRef: Chunk { link: Link }); + +const NUM_EXACT_LIST: usize = 0x100; +const HEADER_SIZE: usize = size_of::(); +const EXACT_MATCH_INCREMENT: usize = 0x8; +const MIN_BLOCK_SIZE: usize = 0x10; +const MAX_EXACT_SIZE: usize = MIN_BLOCK_SIZE + EXACT_MATCH_INCREMENT * (NUM_EXACT_LIST - 1); + +// Free block for allocating memory with exact size +#[repr(C)] +#[derive(Debug)] +struct BlockFree { + size: usize, + link: Link, // singly intrusive linkedlist +} + +// Used block for tracking allocated size and base pointer +#[repr(C)] +#[derive(Debug)] +struct BlockUsed { + size: usize, + payload: usize, +} + +impl BlockFree { + fn new(size: usize) -> Self { + Self { + size, + link: Link::new(), + } + } + + fn set_size(&mut self, size: usize) { + self.size = size; + } + + fn block_size(&self) -> usize { + self.size & SIZE_MASK + } +} + +impl BlockUsed { + fn new(size: usize) -> Self { + Self { size, payload: 0 } + } + + fn set_size(&mut self, size: usize) { + self.size = size; + } + + fn block_size(&self) -> usize { + self.size & SIZE_MASK + } + + fn is_alloced(&self) -> bool { + self.size & ALLOC_MASK == 0 + } + + fn set_alloced(&mut self) { + self.size |= ALLOC_MASK; + } + + fn clear_alloced(&mut self) { + self.size &= SIZE_MASK; + } +} + +intrusive_adapter!(BlockFreeAda = UnsafeRef: BlockFree { link: Link }); + +/// Interior allocator for reserve memory management, +pub struct Reserve { + exact_blocks: [SinglyLinkedList; 256], + large_blocks: SinglyLinkedList, + chunks: SinglyLinkedList, + // The size of memory increment + incr_size: usize, + // statistics + allocated: usize, + total: usize, +} + +impl Reserve { + fn new(size: usize) -> Self { + let exact_blocks: [SinglyLinkedList; 256] = { + let mut exact_blocks: [MaybeUninit>; 256] = + MaybeUninit::uninit_array(); + for block in &mut exact_blocks { + block.write(SinglyLinkedList::new(BlockFreeAda::new())); + } + unsafe { transmute(exact_blocks) } + }; + + let mut reserve = Self { + exact_blocks, + large_blocks: SinglyLinkedList::new(BlockFreeAda::new()), + chunks: SinglyLinkedList::new(ChunkAda::new()), + incr_size: 65536, + allocated: 0, + total: 0, + }; + + // We shouldn't handle the allocation error of reserve memory when initializing, + // If it returns error, the sdk should panic and crash. + unsafe { + reserve.add_chunks(size).unwrap(); + } + reserve + } + + // Find the available free block for memory allocation, + // and bsize must be round to eight + fn get_free_block(&mut self, bsize: usize) -> Option> { + if bsize <= MAX_EXACT_SIZE { + // TODO: for exact size block, maybe we can reuse larger block + // rather than allocating block from chunk + return self.get_exact_block(bsize); + } + + // Loop and find the most available large block + let list = &mut self.large_blocks; + let mut cursor = list.front_mut(); + let mut suit_block: Option<*const BlockFree> = None; + let mut suit_block_size = 0; + while !cursor.is_null() { + let curr_block = cursor.get().unwrap(); + if curr_block.size >= bsize + && (suit_block.is_none() || (suit_block_size > curr_block.size)) + { + suit_block = Some(curr_block as *const BlockFree); + suit_block_size = curr_block.block_size(); + } + cursor.move_next(); + } + + suit_block?; + + cursor = list.front_mut(); + + let mut curr_block_ptr = cursor.get().unwrap() as *const BlockFree; + if curr_block_ptr == suit_block.unwrap() { + return list.pop_front(); + } + + let mut cursor_next = cursor.peek_next(); + while !cursor_next.is_null() { + curr_block_ptr = cursor_next.get().unwrap() as *const BlockFree; + if curr_block_ptr == suit_block.unwrap() { + return cursor.remove_next(); + } + cursor.move_next(); + cursor_next = cursor.peek_next(); + } + + None + } + + fn get_exact_block(&mut self, bsize: usize) -> Option> { + let idx = self.get_list_idx(bsize); + let list = &mut self.exact_blocks[idx]; + list.pop_front() + } + + fn put_free_block(&mut self, block: UnsafeRef) { + let block_size = block.block_size(); + if block_size <= MAX_EXACT_SIZE { + // put block into exact block list + let idx = self.get_list_idx(block_size); + let list = &mut self.exact_blocks[idx]; + list.push_front(block); + } else { + // put block into large block list + let list = &mut self.large_blocks; + list.push_front(block); + } + } + + // Obtain the list index with exact block size + fn get_list_idx(&self, size: usize) -> usize { + assert!(size % EXACT_MATCH_INCREMENT == 0); + if size < MIN_BLOCK_SIZE { + return 0; + } + let idx = (size - MIN_BLOCK_SIZE) / EXACT_MATCH_INCREMENT; + assert!(idx < NUM_EXACT_LIST); + idx + } + + // Reconstruct BlockUsed with BlockFree block_size() and set alloc, return payload addr. + // BlockFree -> BlockUsed -> Payload addr (Used) + fn block_to_payload(&self, block: UnsafeRef) -> usize { + let block_size = block.block_size(); + let mut block_used = BlockUsed::new(block_size); + block_used.set_alloced(); + + let block_used_ptr = UnsafeRef::into_raw(block) as *mut BlockUsed; + unsafe { + block_used_ptr.write(block_used); + // Regular offset shifts count*T bytes + block_used_ptr.byte_offset(HEADER_SIZE as isize) as usize + } + } + + // Reconstruct a new BlockFree with BlockUsed block_size(), return payload addr. + // Payload addr (Used) -> BlockUsed -> BlockFree + fn payload_to_block(&self, payload_addr: usize) -> UnsafeRef { + let payload_ptr = payload_addr as *const u8; + let block_used_ptr = + unsafe { payload_ptr.byte_offset(-(HEADER_SIZE as isize)) as *mut BlockUsed }; + + // Implicitly clear alloc mask, reconstruct new BlockFree + let block_size = unsafe { block_used_ptr.read().block_size() }; + let block_free = BlockFree::new(block_size); + let block_free_ptr = block_used_ptr as *mut BlockFree; + unsafe { + block_free_ptr.write(block_free); + UnsafeRef::from_raw(block_free_ptr) + } + } + + /// Malloc memory + pub fn emalloc(&mut self, size: usize) -> SgxResult { + let mut bsize = round_to!(size + HEADER_SIZE, EXACT_MATCH_INCREMENT); + bsize = bsize.max(MIN_BLOCK_SIZE); + + // Find free block in lists + let mut block = self.get_free_block(bsize); + + if let Some(block) = block { + // No need to set size as free block contains size + return Ok(self.block_to_payload(block)); + }; + + // Alloc new block from chunks + block = self.alloc_from_chunks(bsize); + if block.is_none() { + let chunk_size = size_of::(); + let new_reserve_size = round_to!(bsize + chunk_size, INIT_MEM_SIZE); + unsafe { self.add_chunks(new_reserve_size)? }; + block = self.alloc_from_chunks(bsize); + // Should never happen + if block.is_none() { + return Err(SgxStatus::InvalidParameter); + } + } + + Ok(self.block_to_payload(block.unwrap())) + } + + fn alloc_from_chunks(&mut self, bsize: usize) -> Option> { + let mut addr: usize = 0; + let mut cursor = self.chunks.front_mut(); + while !cursor.is_null() { + let chunk = unsafe { cursor.get_mut().unwrap() }; + if (chunk.size - chunk.used) >= bsize { + addr = chunk.base + chunk.used; + chunk.used += bsize; + break; + } + cursor.move_next(); + } + + if addr == 0 { + None + } else { + let block = BlockFree::new(bsize); + let ptr = addr as *mut BlockFree; + let block = unsafe { + ptr.write(block); + UnsafeRef::from_raw(ptr) + }; + Some(block) + } + } + + /// Free memory + pub fn efree(&mut self, payload_addr: usize) { + let block = self.payload_to_block(payload_addr); + let block_addr = block.as_ref() as *const BlockFree as usize; + let block_size = block.block_size(); + let block_end = block_addr + block_size; + let res = self.find_chunk_with_block(block_addr, block_size); + if res.is_err() { + panic!(); + } + + // TODO: reconfigure the free block, + // merging its dextral block into a large block + let mut cursor = res.unwrap(); + let chunk = unsafe { cursor.get_mut().unwrap() }; + + if block_end - chunk.base == chunk.used { + chunk.used -= block.block_size(); + // TODO: Trigger merging the right-most block into this chunk, + // if and only if the right-most block is in free large block list + return; + } + + self.put_free_block(block); + } + + /// Adding the size of interior memory + /// rsize: memory increment + pub unsafe fn add_chunks(&mut self, rsize: usize) -> SgxResult { + // Here we alloc at least INIT_MEM_SIZE size, + // but commit rsize memory, the remaining memory is COMMIT_ON_DEMAND + let increment = self.incr_size.max(rsize); + + let mut range_manage = RM.get().unwrap().lock(); + let base = range_manage.alloc( + None, + increment + 2 * GUARD_SIZE, + AllocFlags::RESERVED, + PageInfo { + typ: PageType::None, + prot: ProtFlags::NONE, + }, + None, + None, + RangeType::User, + Alloc::Static, + )?; + + let base = range_manage.alloc( + Some(base + GUARD_SIZE), + increment, + AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + RangeType::User, + Alloc::Static, + )?; + + range_manage.commit(base, rsize, RangeType::User)?; + drop(range_manage); + + unsafe { + self.write_chunk(base, increment); + } + + self.incr_size = (self.incr_size * 2).min(MAX_EMALLOC_SIZE); + + Ok(()) + } + + // Parsing the range of unmanaged memory. The function writes a chunk struct in the header of + // unmanaged memory, the written chunk will be responsible for managing the remaining memory. + unsafe fn write_chunk(&mut self, base: usize, size: usize) { + let header_size = size_of::(); + let mem_base = base + header_size; + let mem_size = size - header_size; + + let chunk: Chunk = Chunk::new(mem_base, mem_size); + unsafe { + core::ptr::write(base as *mut Chunk, chunk); + let chunk_ref = UnsafeRef::from_raw(base as *const Chunk); + self.chunks.push_front(chunk_ref); + } + } + + // Find the chunk including the specified block + fn find_chunk_with_block( + &mut self, + block_addr: usize, + block_size: usize, + ) -> SgxResult> { + if block_size == 0 { + return Err(SgxStatus::InvalidParameter); + } + let mut cursor = self.chunks.front_mut(); + while !cursor.is_null() { + let chunk = cursor.get().unwrap(); + if (block_addr >= chunk.base) + && ((block_addr + block_size) <= (chunk.base + chunk.used)) + { + return Ok(cursor); + } + cursor.move_next(); + } + + Err(SgxStatus::InvalidParameter) + } +} diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index 6e2645621..dec63dbe4 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -23,9 +23,9 @@ use core::ptr::NonNull; use sgx_types::error::SgxResult; use sgx_types::error::SgxStatus; +use super::alloc::Alloc; use super::alloc::ResAlloc; use super::alloc::StaticAlloc; -use super::interior::Alloc; #[repr(C)] #[derive(Debug)] diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index d407067ca..c68016a56 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -16,16 +16,17 @@ // under the License.. use crate::arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}; -use crate::edmm::{perm, PageInfo, PageRange, PageType, ProtFlags}; +use crate::emm::{PageInfo, PageRange, PageType, ProtFlags}; use crate::enclave::is_within_enclave; use alloc::boxed::Box; use intrusive_collections::{intrusive_adapter, LinkedListLink, UnsafeRef}; use sgx_types::error::{SgxResult, SgxStatus}; +use super::alloc::Alloc; use super::alloc::{ResAlloc, StaticAlloc}; use super::bitmap::BitArray; -use super::flags::AllocFlags; -use super::interior::Alloc; +use super::ocall; +use super::page::AllocFlags; use super::pfhandler::{PfHandler, PfInfo}; /// Enclave Management Area @@ -179,7 +180,7 @@ impl EMA { }; // Ocall to mmap memory in urts - perm::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags)?; + ocall::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags)?; // Set the corresponding bits of eaccept map if self.alloc_flags.contains(AllocFlags::COMMIT_NOW) { @@ -324,7 +325,7 @@ impl EMA { } let block_length = block_end - block_start; - perm::modify_ocall( + ocall::modify_ocall( block_start, block_length, PageInfo { @@ -351,7 +352,7 @@ impl EMA { } // Notify trimming - perm::modify_ocall( + ocall::modify_ocall( block_start, block_length, PageInfo { @@ -399,7 +400,7 @@ impl EMA { } // Notify modifying permissions - perm::modify_ocall( + ocall::modify_ocall( self.start, self.length, self.info, @@ -434,7 +435,7 @@ impl EMA { }; if new_prot == ProtFlags::NONE { - perm::modify_ocall( + ocall::modify_ocall( self.start, self.length, PageInfo { @@ -472,7 +473,7 @@ impl EMA { return Err(SgxStatus::InvalidParameter); } - perm::modify_ocall( + ocall::modify_ocall( self.start, self.length, info, diff --git a/sgx_trts/src/emm/flags.rs b/sgx_trts/src/emm/flags.rs deleted file mode 100644 index 55e6c3ce3..000000000 --- a/sgx_trts/src/emm/flags.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License.. - -use bitflags::bitflags; - -bitflags! { - pub struct AllocFlags: u32 { - const RESERVED = 0b0001; - const COMMIT_NOW = 0b0010; - const COMMIT_ON_DEMAND = 0b0100; - const GROWSDOWN = 0b00010000; - const GROWSUP = 0b00100000; - const FIXED = 0b01000000; - const SYSTEM = 0b10000000; - } -} diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs index 24eaf2348..743c0700a 100644 --- a/sgx_trts/src/emm/init.rs +++ b/sgx_trts/src/emm/init.rs @@ -15,18 +15,7 @@ // specific language governing permissions and limitations // under the License.. -use sgx_types::error::SgxResult; - -use crate::arch::{Layout, LayoutEntry}; -use crate::edmm::mem::init_segment_emas; -use crate::edmm::{PageInfo, PageType, ProtFlags}; -use crate::emm::flags::AllocFlags; -use crate::emm::interior::Alloc; -use crate::emm::range::{RangeType, EMA_PROT_MASK}; -use crate::enclave::MmLayout; -use crate::{arch, emm::range::RM}; - -use super::interior::{init_reserve_alloc, init_static_alloc}; +use super::alloc::{init_reserve_alloc, init_static_alloc}; use super::range::init_range_manage; pub fn init_emm() { @@ -35,127 +24,252 @@ pub fn init_emm() { init_reserve_alloc(); } -pub fn init_rts_emas() -> SgxResult { - init_segment_emas()?; - // let mut layout = arch::Global::get().layout_table(); - // layout = &layout[..(layout.len() - 1)]; - - // let layout = arch::Global::get().layout_table().split_last().unwrap().1; - let layout = arch::Global::get().layout_table(); - init_rts_contexts_emas(layout, 0)?; - Ok(()) +cfg_if! { + if #[cfg(not(any(feature = "sim", feature = "hyper")))] { + pub use hw::*; + } else { + pub use sw::*; + } } -fn init_rts_contexts_emas(table: &[Layout], offset: usize) -> SgxResult { - unsafe { - for (i, layout) in table.iter().enumerate() { - if is_group_id!(layout.group.id) { - let mut step = 0_usize; - for _ in 0..layout.group.load_times { - step += layout.group.load_step as usize; - init_rts_contexts_emas(&table[i - layout.group.entry_count as usize..i], step)?; +#[cfg(not(any(feature = "sim", feature = "hyper")))] +mod hw { + use crate::arch::{self, Layout, LayoutEntry}; + use crate::elf::program::Type; + use crate::emm::alloc::Alloc; + use crate::emm::layout::LayoutTable; + use crate::emm::page::AllocFlags; + use crate::emm::range::{RangeType, EMA_PROT_MASK, RM}; + use crate::emm::{PageInfo, PageType, ProtFlags}; + use crate::enclave::parse; + use crate::enclave::MmLayout; + use sgx_types::error::{SgxResult, SgxStatus}; + + pub fn init_rts_emas() -> SgxResult { + init_segment_emas()?; + + let layout = arch::Global::get().layout_table(); + init_rts_contexts_emas(layout, 0)?; + Ok(()) + } + + fn init_rts_contexts_emas(table: &[Layout], offset: usize) -> SgxResult { + unsafe { + for (i, layout) in table.iter().enumerate() { + if is_group_id!(layout.group.id) { + let mut step = 0_usize; + for _ in 0..layout.group.load_times { + step += layout.group.load_step as usize; + init_rts_contexts_emas( + &table[i - layout.group.entry_count as usize..i], + step, + )?; + } + } else { + build_rts_context_emas(&layout.entry, offset)?; } - } else { - build_rts_context_emas(&layout.entry, offset)?; } + Ok(()) } - Ok(()) } -} -fn build_rts_context_emas(entry: &LayoutEntry, offset: usize) -> SgxResult { - if entry.id == arch::LAYOUT_ID_USER_REGION { - return Ok(()); - } + fn build_rts_context_emas(entry: &LayoutEntry, offset: usize) -> SgxResult { + if entry.id == arch::LAYOUT_ID_USER_REGION { + return Ok(()); + } + + let rva = offset + (entry.rva as usize); + assert!(is_page_aligned!(rva)); + + // TODO: not sure get_enclave_base() equal to elrange_base or image_base + let addr = MmLayout::image_base() + rva; + let size = (entry.page_count << arch::SE_PAGE_SHIFT) as usize; + let mut range_manage = RM.get().unwrap().lock(); - let rva = offset + (entry.rva as usize); - assert!(is_page_aligned!(rva)); - - // TODO: not sure get_enclave_base() equal to elrange_base or image_base - let addr = MmLayout::image_base() + rva; - let size = (entry.page_count << arch::SE_PAGE_SHIFT) as usize; - let mut range_manage = RM.get().unwrap().lock(); - - // entry is guard page or has EREMOVE, build a reserved ema - if (entry.si_flags == 0) || (entry.attributes & arch::PAGE_ATTR_EREMOVE != 0) { - range_manage.init_static_region( - addr, - size, - AllocFlags::RESERVED | AllocFlags::SYSTEM, - PageInfo { - typ: PageType::None, - prot: ProtFlags::NONE, - }, - None, - None, - )?; - return Ok(()); + // entry is guard page or has EREMOVE, build a reserved ema + if (entry.si_flags == 0) || (entry.attributes & arch::PAGE_ATTR_EREMOVE != 0) { + range_manage.init_static_region( + addr, + size, + AllocFlags::RESERVED | AllocFlags::SYSTEM, + PageInfo { + typ: PageType::None, + prot: ProtFlags::NONE, + }, + None, + None, + )?; + return Ok(()); + } + + let post_remove = (entry.attributes & arch::PAGE_ATTR_POST_REMOVE) != 0; + let post_add = (entry.attributes & arch::PAGE_ATTR_POST_ADD) != 0; + let static_min = ((entry.attributes & arch::PAGE_ATTR_EADD) != 0) && !post_remove; + + if post_remove { + // TODO: maybe AllocFlags need more flags or PageType is not None + range_manage.init_static_region( + addr, + size, + AllocFlags::SYSTEM, + PageInfo { + typ: PageType::None, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + )?; + + range_manage.dealloc(addr, size, RangeType::Rts)?; + } + + if post_add { + let commit_direction = if entry.id == arch::LAYOUT_ID_STACK_MAX + || entry.id == arch::LAYOUT_ID_STACK_DYN_MAX + || entry.id == arch::LAYOUT_ID_STACK_DYN_MIN + { + AllocFlags::GROWSDOWN + } else { + AllocFlags::GROWSUP + }; + + // TODO: revise alloc and not use int + range_manage.alloc( + Some(addr), + size, + AllocFlags::COMMIT_ON_DEMAND + | commit_direction + | AllocFlags::SYSTEM + | AllocFlags::FIXED, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + RangeType::Rts, + Alloc::Reserve, + )?; + } else if static_min { + let info = if entry.id == arch::LAYOUT_ID_TCS { + PageInfo { + typ: PageType::Tcs, + prot: ProtFlags::NONE, + } + } else { + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::from_bits_truncate( + (entry.si_flags as usize & EMA_PROT_MASK) as u8, + ), + } + }; + range_manage.init_static_region(addr, size, AllocFlags::SYSTEM, info, None, None)?; + } + + Ok(()) } - let post_remove = (entry.attributes & arch::PAGE_ATTR_POST_REMOVE) != 0; - let post_add = (entry.attributes & arch::PAGE_ATTR_POST_ADD) != 0; - let static_min = ((entry.attributes & arch::PAGE_ATTR_EADD) != 0) && !post_remove; - - if post_remove { - // TODO: maybe AllocFlags need more flags or PageType is not None - range_manage.init_static_region( - addr, - size, - AllocFlags::SYSTEM, - PageInfo { - typ: PageType::None, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - )?; - - range_manage.dealloc(addr, size, RangeType::Rts)?; + pub fn expand_stack_epc_pages(addr: usize, count: usize) -> SgxResult { + ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); + + LayoutTable::new() + .check_dyn_range(addr, count, None) + .ok_or(SgxStatus::InvalidParameter)?; + + let mut range_manage = RM.get().unwrap().lock(); + range_manage.commit(addr, count << arch::SE_PAGE_SHIFT, RangeType::Rts)?; + + Ok(()) } - if post_add { - let commit_direction = if entry.id == arch::LAYOUT_ID_STACK_MAX - || entry.id == arch::LAYOUT_ID_STACK_DYN_MAX - || entry.id == arch::LAYOUT_ID_STACK_DYN_MIN - { - AllocFlags::GROWSDOWN - } else { - AllocFlags::GROWSUP - }; - - // TODO: revise alloc and not use int - range_manage.alloc_inner( - Some(addr), - size, - AllocFlags::COMMIT_ON_DEMAND - | commit_direction - | AllocFlags::SYSTEM - | AllocFlags::FIXED, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - RangeType::Rts, - Alloc::Reserve, - )?; - } else if static_min { - let info = if entry.id == arch::LAYOUT_ID_TCS { - PageInfo { - typ: PageType::Tcs, - prot: ProtFlags::NONE, + pub fn change_perm() -> SgxResult { + let elf = parse::new_elf()?; + let text_relo = parse::has_text_relo()?; + + let base = MmLayout::image_base(); + let mut range_manage = RM.get().unwrap().lock(); + for phdr in elf.program_iter() { + let typ = phdr.get_type().unwrap_or(Type::Null); + if typ == Type::Load && text_relo && !phdr.flags().is_write() { + let mut perm = 0_u64; + let start = base + trim_to_page!(phdr.virtual_addr() as usize); + let end = + base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); + let size = end - start; + + if phdr.flags().is_read() { + perm |= arch::SGX_EMA_PROT_READ; + } + if phdr.flags().is_execute() { + perm |= arch::SGX_EMA_PROT_EXEC; + } + + let prot = ProtFlags::from_bits_truncate(perm as u8); + range_manage.modify_perms(start, size, prot, RangeType::Rts)?; } - } else { - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::from_bits_truncate( - (entry.si_flags as usize & EMA_PROT_MASK) as u8, - ), + if typ == Type::GnuRelro { + let start = base + trim_to_page!(phdr.virtual_addr() as usize); + let end = + base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); + let size = end - start; + + if size > 0 { + range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; + } } - }; - range_manage.init_static_region(addr, size, AllocFlags::SYSTEM, info, None, None)?; + } + + let layout_table = arch::Global::get().layout_table(); + if let Some(layout) = layout_table.iter().find(|layout| unsafe { + (layout.entry.id == arch::LAYOUT_ID_RSRV_MIN) + && (layout.entry.si_flags == arch::SI_FLAGS_RWX) + && (layout.entry.page_count > 0) + }) { + let start = base + unsafe { layout.entry.rva as usize }; + let size = unsafe { layout.entry.page_count as usize } << arch::SE_PAGE_SHIFT; + + range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; + } + Ok(()) } - Ok(()) + pub fn init_segment_emas() -> SgxResult { + let elf = parse::new_elf()?; + let text_relo = parse::has_text_relo()?; + + let base = MmLayout::image_base(); + for phdr in elf.program_iter() { + let typ = phdr.get_type().unwrap_or(Type::Null); + + if typ == Type::Load { + let mut perm = ProtFlags::R; + let start = base + trim_to_page!(phdr.virtual_addr() as usize); + let end = + base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); + + if phdr.flags().is_write() || text_relo { + perm |= ProtFlags::W; + } + if phdr.flags().is_execute() { + perm |= ProtFlags::X; + } + + let mut range_manage = RM.get().unwrap().lock(); + range_manage.init_static_region( + start, + end - start, + AllocFlags::SYSTEM, + PageInfo { + typ: PageType::Reg, + prot: perm, + }, + None, + None, + )?; + } + } + + Ok(()) + } } diff --git a/sgx_trts/src/emm/interior.rs b/sgx_trts/src/emm/interior.rs deleted file mode 100644 index 6dfc21f53..000000000 --- a/sgx_trts/src/emm/interior.rs +++ /dev/null @@ -1,482 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License.. - -use buddy_system_allocator::LockedHeap; -use intrusive_collections::intrusive_adapter; -use intrusive_collections::singly_linked_list::CursorMut; -use intrusive_collections::singly_linked_list::{Link, SinglyLinkedList}; -use intrusive_collections::UnsafeRef; - -use core::mem::size_of; -use core::mem::transmute; -use core::mem::MaybeUninit; -use spin::{Mutex, Once}; - -use super::flags::AllocFlags; -use super::range::{RangeType, RM}; -use sgx_types::error::{SgxResult, SgxStatus}; - -// The size of fixed static memory for Static Allocator -const STATIC_MEM_SIZE: usize = 65536; - -// The size of initial reserve memory for Reserve Allocator -const INIT_MEM_SIZE: usize = 65536; - -// The size of guard pages -const GUARD_SIZE: usize = 0x8000; - -// The max allocated size of Reserve Allocator -const MAX_EMALLOC_SIZE: usize = 0x10000000; - -const ALLOC_MASK: usize = 1; -const SIZE_MASK: usize = !(EXACT_MATCH_INCREMENT - 1); - -/// Lowest level: Allocator for static memory -pub static STATIC: Once> = Once::new(); - -/// Static memory for allocation -static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; - -/// Init lowest level static memory allocator -pub fn init_static_alloc() { - STATIC.call_once(|| { - let static_alloc = LockedHeap::empty(); - unsafe { - static_alloc - .lock() - .init(STATIC_MEM.as_ptr() as usize, STATIC_MEM_SIZE) - }; - static_alloc - }); -} - -/// Second level: Allocator for reserve memory -pub static RES_ALLOCATOR: Once> = Once::new(); - -/// Init reserve memory allocator -/// init_reserve_alloc() need to be called after init_static_alloc() -pub fn init_reserve_alloc() { - RES_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); -} - -// Enum for allocator types -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum Alloc { - Static, - Reserve, -} - -// Chunk manages memory range. -// The Chunk structure is filled into the layout before the base pointer. -#[derive(Debug)] -struct Chunk { - base: usize, - size: usize, - used: usize, - link: Link, // singly intrusive linkedlist -} - -impl Chunk { - fn new(base: usize, size: usize) -> Self { - Self { - base, - size, - used: 0, - link: Link::new(), - } - } -} - -intrusive_adapter!(ChunkAda = UnsafeRef: Chunk { link: Link }); - -const NUM_EXACT_LIST: usize = 0x100; -const HEADER_SIZE: usize = size_of::(); -const EXACT_MATCH_INCREMENT: usize = 0x8; -const MIN_BLOCK_SIZE: usize = 0x10; -const MAX_EXACT_SIZE: usize = MIN_BLOCK_SIZE + EXACT_MATCH_INCREMENT * (NUM_EXACT_LIST - 1); - -// Free block for allocating memory with exact size -#[repr(C)] -#[derive(Debug)] -struct BlockFree { - size: usize, - link: Link, // singly intrusive linkedlist -} - -// Used block for tracking allocated size and base pointer -#[repr(C)] -#[derive(Debug)] -struct BlockUsed { - size: usize, - payload: usize, -} - -impl BlockFree { - fn new(size: usize) -> Self { - Self { - size, - link: Link::new(), - } - } - - fn set_size(&mut self, size: usize) { - self.size = size; - } - - fn block_size(&self) -> usize { - self.size & SIZE_MASK - } -} - -impl BlockUsed { - fn new(size: usize) -> Self { - Self { size, payload: 0 } - } - - fn set_size(&mut self, size: usize) { - self.size = size; - } - - fn block_size(&self) -> usize { - self.size & SIZE_MASK - } - - fn is_alloced(&self) -> bool { - self.size & ALLOC_MASK == 0 - } - - fn set_alloced(&mut self) { - self.size |= ALLOC_MASK; - } - - fn clear_alloced(&mut self) { - self.size &= SIZE_MASK; - } -} - -intrusive_adapter!(BlockFreeAda = UnsafeRef: BlockFree { link: Link }); - -/// Interior allocator for reserve memory management, -pub struct Reserve { - exact_blocks: [SinglyLinkedList; 256], - large_blocks: SinglyLinkedList, - chunks: SinglyLinkedList, - // The size of memory increment - incr_size: usize, - // statistics - allocated: usize, - total: usize, -} - -impl Reserve { - fn new(size: usize) -> Self { - let exact_blocks: [SinglyLinkedList; 256] = { - let mut exact_blocks: [MaybeUninit>; 256] = - MaybeUninit::uninit_array(); - for block in &mut exact_blocks { - block.write(SinglyLinkedList::new(BlockFreeAda::new())); - } - unsafe { transmute(exact_blocks) } - }; - - let mut reserve = Self { - exact_blocks, - large_blocks: SinglyLinkedList::new(BlockFreeAda::new()), - chunks: SinglyLinkedList::new(ChunkAda::new()), - incr_size: 65536, - allocated: 0, - total: 0, - }; - - // We shouldn't handle the allocation error of reserve memory when initializing, - // If it returns error, the sdk should panic and crash. - unsafe { - reserve.add_chunks(size).unwrap(); - } - reserve - } - - // Find the available free block for memory allocation, - // and bsize must be round to eight - fn get_free_block(&mut self, bsize: usize) -> Option> { - if bsize <= MAX_EXACT_SIZE { - // TODO: for exact size block, maybe we can reuse larger block - // rather than allocating block from chunk - return self.get_exact_block(bsize); - } - - // Loop and find the most available large block - let list = &mut self.large_blocks; - let mut cursor = list.front_mut(); - let mut suit_block: Option<*const BlockFree> = None; - let mut suit_block_size = 0; - while !cursor.is_null() { - let curr_block = cursor.get().unwrap(); - if curr_block.size >= bsize - && (suit_block.is_none() || (suit_block_size > curr_block.size)) - { - suit_block = Some(curr_block as *const BlockFree); - suit_block_size = curr_block.block_size(); - } - cursor.move_next(); - } - - suit_block?; - - cursor = list.front_mut(); - - let mut curr_block_ptr = cursor.get().unwrap() as *const BlockFree; - if curr_block_ptr == suit_block.unwrap() { - return list.pop_front(); - } - - let mut cursor_next = cursor.peek_next(); - while !cursor_next.is_null() { - curr_block_ptr = cursor_next.get().unwrap() as *const BlockFree; - if curr_block_ptr == suit_block.unwrap() { - return cursor.remove_next(); - } - cursor.move_next(); - cursor_next = cursor.peek_next(); - } - - None - } - - fn get_exact_block(&mut self, bsize: usize) -> Option> { - let idx = self.get_list_idx(bsize); - let list = &mut self.exact_blocks[idx]; - list.pop_front() - } - - fn put_free_block(&mut self, block: UnsafeRef) { - let block_size = block.block_size(); - if block_size <= MAX_EXACT_SIZE { - // put block into exact block list - let idx = self.get_list_idx(block_size); - let list = &mut self.exact_blocks[idx]; - list.push_front(block); - } else { - // put block into large block list - let list = &mut self.large_blocks; - list.push_front(block); - } - } - - // Obtain the list index with exact block size - fn get_list_idx(&self, size: usize) -> usize { - assert!(size % EXACT_MATCH_INCREMENT == 0); - if size < MIN_BLOCK_SIZE { - return 0; - } - let idx = (size - MIN_BLOCK_SIZE) / EXACT_MATCH_INCREMENT; - assert!(idx < NUM_EXACT_LIST); - idx - } - - // Reconstruct BlockUsed with BlockFree block_size() and set alloc, return payload addr. - // BlockFree -> BlockUsed -> Payload addr (Used) - fn block_to_payload(&self, block: UnsafeRef) -> usize { - let block_size = block.block_size(); - let mut block_used = BlockUsed::new(block_size); - block_used.set_alloced(); - - let block_used_ptr = UnsafeRef::into_raw(block) as *mut BlockUsed; - unsafe { - block_used_ptr.write(block_used); - // Regular offset shifts count*T bytes - block_used_ptr.byte_offset(HEADER_SIZE as isize) as usize - } - } - - // Reconstruct a new BlockFree with BlockUsed block_size(), return payload addr. - // Payload addr (Used) -> BlockUsed -> BlockFree - fn payload_to_block(&self, payload_addr: usize) -> UnsafeRef { - let payload_ptr = payload_addr as *const u8; - let block_used_ptr = - unsafe { payload_ptr.byte_offset(-(HEADER_SIZE as isize)) as *mut BlockUsed }; - - // Implicitly clear alloc mask, reconstruct new BlockFree - let block_size = unsafe { block_used_ptr.read().block_size() }; - let block_free = BlockFree::new(block_size); - let block_free_ptr = block_used_ptr as *mut BlockFree; - unsafe { - block_free_ptr.write(block_free); - UnsafeRef::from_raw(block_free_ptr) - } - } - - /// Malloc memory - pub fn emalloc(&mut self, size: usize) -> SgxResult { - let mut bsize = round_to!(size + HEADER_SIZE, EXACT_MATCH_INCREMENT); - bsize = bsize.max(MIN_BLOCK_SIZE); - - // Find free block in lists - let mut block = self.get_free_block(bsize); - - if let Some(block) = block { - // No need to set size as free block contains size - return Ok(self.block_to_payload(block)); - }; - - // Alloc new block from chunks - block = self.alloc_from_chunks(bsize); - if block.is_none() { - let chunk_size = size_of::(); - let new_reserve_size = round_to!(bsize + chunk_size, INIT_MEM_SIZE); - unsafe { self.add_chunks(new_reserve_size)? }; - block = self.alloc_from_chunks(bsize); - // Should never happen - if block.is_none() { - return Err(SgxStatus::InvalidParameter); - } - } - - Ok(self.block_to_payload(block.unwrap())) - } - - fn alloc_from_chunks(&mut self, bsize: usize) -> Option> { - let mut addr: usize = 0; - let mut cursor = self.chunks.front_mut(); - while !cursor.is_null() { - let chunk = unsafe { cursor.get_mut().unwrap() }; - if (chunk.size - chunk.used) >= bsize { - addr = chunk.base + chunk.used; - chunk.used += bsize; - break; - } - cursor.move_next(); - } - - if addr == 0 { - None - } else { - let block = BlockFree::new(bsize); - let ptr = addr as *mut BlockFree; - let block = unsafe { - ptr.write(block); - UnsafeRef::from_raw(ptr) - }; - Some(block) - } - } - - /// Free memory - pub fn efree(&mut self, payload_addr: usize) { - let block = self.payload_to_block(payload_addr); - let block_addr = block.as_ref() as *const BlockFree as usize; - let block_size = block.block_size(); - let block_end = block_addr + block_size; - let res = self.find_chunk_with_block(block_addr, block_size); - if res.is_err() { - panic!(); - } - - // TODO: reconfigure the free block, - // merging its dextral block into a large block - let mut cursor = res.unwrap(); - let chunk = unsafe { cursor.get_mut().unwrap() }; - - if block_end - chunk.base == chunk.used { - chunk.used -= block.block_size(); - // TODO: Trigger merging the right-most block into this chunk, - // if and only if the right-most block is in free large block list - return; - } - - self.put_free_block(block); - } - - /// Adding the size of interior memory - /// rsize: memory increment - pub unsafe fn add_chunks(&mut self, rsize: usize) -> SgxResult { - // Here we alloc at least INIT_MEM_SIZE size, - // but commit rsize memory, the remaining memory is COMMIT_ON_DEMAND - let increment = self.incr_size.max(rsize); - - let mut range_manage = RM.get().unwrap().lock(); - let base = range_manage.alloc( - None, - increment + 2 * GUARD_SIZE, - AllocFlags::RESERVED.bits() as usize, - None, - None, - RangeType::User, - Alloc::Static, - )?; - - let base = range_manage.alloc( - Some(base + GUARD_SIZE), - increment, - (AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED).bits() as usize, - None, - None, - RangeType::User, - Alloc::Static, - )?; - - range_manage.commit(base, rsize, RangeType::User)?; - drop(range_manage); - - unsafe { - self.write_chunk(base, increment); - } - - self.incr_size = (self.incr_size * 2).min(MAX_EMALLOC_SIZE); - - Ok(()) - } - - // Parsing the range of unmanaged memory. The function writes a chunk struct in the header of - // unmanaged memory, the written chunk will be responsible for managing the remaining memory. - unsafe fn write_chunk(&mut self, base: usize, size: usize) { - let header_size = size_of::(); - let mem_base = base + header_size; - let mem_size = size - header_size; - - let chunk: Chunk = Chunk::new(mem_base, mem_size); - unsafe { - core::ptr::write(base as *mut Chunk, chunk); - let chunk_ref = UnsafeRef::from_raw(base as *const Chunk); - self.chunks.push_front(chunk_ref); - } - } - - // Find the chunk including the specified block - fn find_chunk_with_block( - &mut self, - block_addr: usize, - block_size: usize, - ) -> SgxResult> { - if block_size == 0 { - return Err(SgxStatus::InvalidParameter); - } - let mut cursor = self.chunks.front_mut(); - while !cursor.is_null() { - let chunk = cursor.get().unwrap(); - if (block_addr >= chunk.base) - && ((block_addr + block_size) <= (chunk.base + chunk.used)) - { - return Ok(cursor); - } - cursor.move_next(); - } - - Err(SgxStatus::InvalidParameter) - } -} diff --git a/sgx_trts/src/edmm/layout.rs b/sgx_trts/src/emm/layout.rs similarity index 100% rename from sgx_trts/src/edmm/layout.rs rename to sgx_trts/src/emm/layout.rs diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index 35a137fd0..291df3c0d 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -15,13 +15,19 @@ // specific language governing permissions and limitations // under the License.. +#[cfg(not(any(feature = "sim", feature = "hyper")))] pub(crate) mod alloc; pub(crate) mod bitmap; pub(crate) mod ema; -pub(crate) mod flags; pub(crate) mod init; #[cfg(not(any(feature = "sim", feature = "hyper")))] -pub(crate) mod interior; +pub(crate) mod layout; +pub(crate) mod ocall; +pub(crate) mod page; pub(crate) mod pfhandler; pub(crate) mod range; -pub(crate) mod user; +pub(crate) mod tcs; +pub(crate) mod trim; + +pub use ocall::{modpr_ocall, mprotect_ocall}; +pub use page::{apply_epc_pages, trim_epc_pages, PageInfo, PageRange, PageType, ProtFlags}; diff --git a/sgx_trts/src/edmm/perm.rs b/sgx_trts/src/emm/ocall.rs similarity index 88% rename from sgx_trts/src/edmm/perm.rs rename to sgx_trts/src/emm/ocall.rs index 31368064b..932cdd010 100644 --- a/sgx_trts/src/edmm/perm.rs +++ b/sgx_trts/src/emm/ocall.rs @@ -27,51 +27,12 @@ cfg_if! { mod hw { use crate::arch::SE_PAGE_SHIFT; use crate::call::{ocall, OCallIndex, OcAlloc}; - use crate::edmm::{PageInfo, PageType}; - use crate::emm::flags::AllocFlags; + use crate::emm::page::AllocFlags; + use crate::emm::{PageInfo, PageType}; use alloc::boxed::Box; use core::convert::Into; use sgx_types::error::{SgxResult, SgxStatus}; use sgx_types::types::ProtectPerm; - - #[repr(C)] - #[derive(Clone, Copy, Debug, Default)] - struct ChangePermOcall { - addr: usize, - size: usize, - perm: u64, - } - - pub fn modpr_ocall(addr: usize, count: usize, perm: ProtectPerm) -> SgxResult { - let mut change = Box::try_new_in( - ChangePermOcall { - addr, - size: count << SE_PAGE_SHIFT, - perm: Into::::into(perm) as u64, - }, - OcAlloc, - ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::Modpr, Some(change.as_mut())) - } - - pub fn mprotect_ocall(addr: usize, count: usize, perm: ProtectPerm) -> SgxResult { - let mut change = Box::try_new_in( - ChangePermOcall { - addr, - size: count << SE_PAGE_SHIFT, - perm: Into::::into(perm) as u64, - }, - OcAlloc, - ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::Mprotect, Some(change.as_mut())) - } - - // In keeping with Intel SDK, here we use the name page_properties, - // but page_type: PageType is more appropriate #[repr(C)] #[derive(Clone, Copy, Debug, Default)] struct EmmAllocOcall { @@ -82,7 +43,6 @@ mod hw { alloc_flags: u32, } - /// FIXME: fake alloc pub fn alloc_ocall( addr: usize, length: usize, @@ -91,7 +51,7 @@ mod hw { ) -> SgxResult { let mut change = Box::try_new_in( EmmAllocOcall { - retval: 0, // not sure + retval: 0, addr, size: length, page_properties: Into::::into(page_type) as u32, @@ -104,8 +64,6 @@ mod hw { ocall(OCallIndex::Alloc, Some(change.as_mut())) } - // In keeping with Intel SDK, here we use the name flags_from (si_flags), - // but we rename si_flags to page_info, here info_from: PageInfo is more appropriate #[repr(C)] #[derive(Clone, Copy, Debug, Default)] struct EmmModifyOcall { @@ -116,7 +74,6 @@ mod hw { flags_to: u32, } - /// FIXME: fake modify pub fn modify_ocall( addr: usize, length: usize, @@ -137,6 +94,42 @@ mod hw { ocall(OCallIndex::Modify, Some(change.as_mut())) } + + #[repr(C)] + #[derive(Clone, Copy, Debug, Default)] + struct ChangePermOcall { + addr: usize, + size: usize, + perm: u64, + } + + pub fn modpr_ocall(addr: usize, count: usize, perm: ProtectPerm) -> SgxResult { + let mut change = Box::try_new_in( + ChangePermOcall { + addr, + size: count << SE_PAGE_SHIFT, + perm: Into::::into(perm) as u64, + }, + OcAlloc, + ) + .map_err(|_| SgxStatus::OutOfMemory)?; + + ocall(OCallIndex::Modpr, Some(change.as_mut())) + } + + pub fn mprotect_ocall(addr: usize, count: usize, perm: ProtectPerm) -> SgxResult { + let mut change = Box::try_new_in( + ChangePermOcall { + addr, + size: count << SE_PAGE_SHIFT, + perm: Into::::into(perm) as u64, + }, + OcAlloc, + ) + .map_err(|_| SgxStatus::OutOfMemory)?; + + ocall(OCallIndex::Mprotect, Some(change.as_mut())) + } } #[cfg(any(feature = "sim", feature = "hyper"))] @@ -144,6 +137,28 @@ mod sw { use sgx_types::error::SgxResult; use sgx_types::types::ProtectPerm; + #[allow(clippy::unnecessary_wraps)] + #[inline] + pub fn alloc_ocall( + _addr: usize, + _length: usize, + _page_type: PageType, + _alloc_flags: AllocFlags, + ) -> SgxResult { + Ok(()) + } + + #[allow(clippy::unnecessary_wraps)] + #[inline] + pub fn modify_ocall( + _addr: usize, + _length: usize, + _info_from: PageInfo, + _info_to: PageInfo, + ) -> SgxResult { + Ok(()) + } + #[allow(clippy::unnecessary_wraps)] #[inline] pub fn modpr_ocall(_addr: usize, _count: usize, _perm: ProtectPerm) -> SgxResult { diff --git a/sgx_trts/src/edmm/epc.rs b/sgx_trts/src/emm/page.rs similarity index 77% rename from sgx_trts/src/edmm/epc.rs rename to sgx_trts/src/emm/page.rs index a1117d446..a74eeb0cc 100644 --- a/sgx_trts/src/edmm/epc.rs +++ b/sgx_trts/src/emm/page.rs @@ -15,22 +15,35 @@ // specific language governing permissions and limitations // under the License.. -use crate::arch::{SecInfo, SE_PAGE_SHIFT, SE_PAGE_SIZE}; +use crate::arch::{self, Secinfo, SE_PAGE_SHIFT, SE_PAGE_SIZE}; +use crate::emm::layout::LayoutTable; +use crate::emm::trim; use crate::enclave::is_within_enclave; use crate::inst::EncluInst; +use bitflags::bitflags; use core::num::NonZeroUsize; use sgx_types::error::{SgxResult, SgxStatus}; use sgx_types::marker::ContiguousMemory; +bitflags! { + pub struct AllocFlags: u32 { + const RESERVED = 0b0001; + const COMMIT_NOW = 0b0010; + const COMMIT_ON_DEMAND = 0b0100; + const GROWSDOWN = 0b00010000; + const GROWSUP = 0b00100000; + const FIXED = 0b01000000; + const SYSTEM = 0b10000000; + } +} + impl_enum! { #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PageType { - // Secs = 0, None = 0, Tcs = 1, Reg = 2, - // Va = 3, Trim = 4, Frist = 5, Rest = 6, @@ -225,3 +238,49 @@ impl Page { EncluInst::emodpe(&secinfo, self.addr).map_err(|_| SgxStatus::Unexpected) } } + +pub fn apply_epc_pages(addr: usize, count: usize) -> SgxResult { + ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); + + if let Some(attr) = LayoutTable::new().check_dyn_range(addr, count, None) { + let pages = PageRange::new( + addr, + count, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, + }, + )?; + if (attr.attr & arch::PAGE_DIR_GROW_DOWN) == 0 { + pages.accept_forward() + } else { + pages.accept_backward() + } + } else { + Err(SgxStatus::InvalidParameter) + } +} + +pub fn trim_epc_pages(addr: usize, count: usize) -> SgxResult { + ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); + + LayoutTable::new() + .check_dyn_range(addr, count, None) + .ok_or(SgxStatus::InvalidParameter)?; + + trim::trim_range(addr, count)?; + + let pages = PageRange::new( + addr, + count, + PageInfo { + typ: PageType::Trim, + prot: ProtFlags::MODIFIED, + }, + )?; + pages.accept_forward()?; + + trim::trim_range_commit(addr, count)?; + + Ok(()) +} diff --git a/sgx_trts/src/emm/pfhandler.rs b/sgx_trts/src/emm/pfhandler.rs index edd507580..a6360251f 100644 --- a/sgx_trts/src/emm/pfhandler.rs +++ b/sgx_trts/src/emm/pfhandler.rs @@ -16,9 +16,9 @@ // under the License.. use crate::{ - edmm::ProtFlags, + emm::ProtFlags, emm::{ - flags::AllocFlags, + page::AllocFlags, range::{RangeType, RM}, }, veh::HandleResult, diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index 99857b64c..14020efb8 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -17,8 +17,8 @@ use crate::{ arch::SE_PAGE_SIZE, - edmm::{PageInfo, PageType, ProtFlags}, - enclave::{is_within_enclave, MmLayout}, + emm::{PageInfo, PageType, ProtFlags}, + enclave::{is_within_enclave, is_within_rts_range, is_within_user_range, MmLayout}, sync::SpinReentrantMutex, }; use alloc::boxed::Box; @@ -27,22 +27,20 @@ use sgx_types::error::{SgxResult, SgxStatus}; use spin::Once; use super::{ - alloc::{ResAlloc, StaticAlloc}, + alloc::{Alloc, ResAlloc, StaticAlloc}, ema::{EmaAda, EMA}, - flags::AllocFlags, - interior::Alloc, + page::AllocFlags, pfhandler::{PfHandler, PfInfo}, - user::{is_within_rts_range, is_within_user_range}, }; -const ALLOC_FLAGS_SHIFT: usize = 0; -const ALLOC_FLAGS_MASK: usize = 0xFF << ALLOC_FLAGS_SHIFT; +pub const ALLOC_FLAGS_SHIFT: usize = 0; +pub const ALLOC_FLAGS_MASK: usize = 0xFF << ALLOC_FLAGS_SHIFT; -const PAGE_TYPE_SHIFT: usize = 8; -const PAGE_TYPE_MASK: usize = 0xFF << PAGE_TYPE_SHIFT; +pub const PAGE_TYPE_SHIFT: usize = 8; +pub const PAGE_TYPE_MASK: usize = 0xFF << PAGE_TYPE_SHIFT; -const ALLIGNMENT_SHIFT: usize = 24; -const ALLIGNMENT_MASK: usize = 0xFF << ALLIGNMENT_SHIFT; +pub const ALLIGNMENT_SHIFT: usize = 24; +pub const ALLIGNMENT_MASK: usize = 0xFF << ALLIGNMENT_SHIFT; pub const EMA_PROT_MASK: usize = 0x7; @@ -105,7 +103,7 @@ impl RangeManage { )?, ResAlloc, ); - // new_ema.alloc()?; + if !alloc_flags.contains(AllocFlags::RESERVED) { new_ema.set_eaccept_map_full()?; } @@ -156,156 +154,6 @@ impl RangeManage { /// Allocate a new memory region in enclave address space (ELRANGE). pub fn alloc( - &mut self, - addr: Option, - size: usize, - flags: usize, - handler: Option, - priv_data: Option<*mut PfInfo>, - typ: RangeType, - alloc: Alloc, - ) -> SgxResult { - let addr = addr.unwrap_or(0); - // let alloc_flags = - // AllocFlags::try_from(((flags & ALLOC_FLAGS_MASK) >> ALLOC_FLAGS_SHIFT) as u32)?; - - let alloc_flags = - AllocFlags::from_bits(((flags & ALLOC_FLAGS_MASK) >> ALLOC_FLAGS_SHIFT) as u32) - .ok_or(SgxStatus::InvalidParameter)?; - - // TODO: uncouple EMA and range management - // if alloc_flags.contains(AllocFlags::SYSTEM) { - // return Err(SgxStatus::InvalidParameter); - // } - - let mut page_type = - match PageType::try_from(((flags & PAGE_TYPE_MASK) >> PAGE_TYPE_SHIFT) as u8) { - Ok(typ) => typ, - Err(_) => return Err(SgxStatus::InvalidParameter), - }; - - if page_type == PageType::None { - page_type = PageType::Reg; - } - - if (size % SE_PAGE_SIZE) > 0 { - return Err(SgxStatus::InvalidParameter); - } - - let mut align_flag: u8 = ((flags & ALLIGNMENT_MASK) >> ALLIGNMENT_SHIFT) as u8; - if align_flag == 0 { - align_flag = 12; - } - if align_flag < 12 { - return Err(SgxStatus::InvalidParameter); - } - let align_mask: usize = (1 << align_flag) - 1; - - if (addr & align_mask) > 0 { - return Err(SgxStatus::InvalidParameter); - } - - if (addr > 0) && !is_within_enclave(addr as *const u8, size) { - return Err(SgxStatus::InvalidParameter); - } - - let info = if alloc_flags.contains(AllocFlags::RESERVED) { - PageInfo { - prot: ProtFlags::NONE, - typ: PageType::None, - } - } else { - PageInfo { - prot: ProtFlags::R | ProtFlags::W, - typ: page_type, - } - }; - - let mut alloc_addr: Option = None; - let mut alloc_next_ema: Option> = None; - - if addr > 0 { - let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); - // FIXME: search_ema_range implicitly contains splitting ema! - let range = self.search_ema_range(addr, addr + size, typ, false); - - match range { - // exist in emas list - Ok(_) => { - // TODO: realloc EMA from reserve - match self.clear_reserved_emas(addr, addr + size, typ, alloc) { - Ok(ema) => { - alloc_addr = Some(addr); - alloc_next_ema = Some(ema); - } - Err(_) => { - if is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); - } - } - } - } - // not exist in emas list - Err(_) => { - let next_ema = self.find_free_region_at(addr, size, typ); - if next_ema.is_err() && is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); - } - } - }; - }; - - if alloc_addr.is_none() { - let (free_addr, next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; - alloc_addr = Some(free_addr); - alloc_next_ema = Some(next_ema); - } - - // let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; - - let new_ema_ref = match alloc { - Alloc::Reserve => { - let mut new_ema = Box::::new_in( - EMA::new( - alloc_addr.unwrap(), - size, - alloc_flags, - info, - handler, - priv_data, - Alloc::Reserve, - )?, - ResAlloc, - ); - new_ema.alloc()?; - - unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } - } - Alloc::Static => { - let mut new_ema = Box::::new_in( - EMA::new( - alloc_addr.unwrap(), - size, - alloc_flags, - info, - handler, - priv_data, - Alloc::Static, - )?, - StaticAlloc, - ); - new_ema.alloc()?; - - unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } - } - }; - - alloc_next_ema.unwrap().insert_before(new_ema_ref); - Ok(alloc_addr.unwrap()) - } - - /// Allocate a new memory region in enclave address space (ELRANGE). - pub fn alloc_inner( &mut self, addr: Option, size: usize, @@ -339,25 +187,22 @@ impl RangeManage { if addr > 0 { let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); - // FIXME: search_ema_range implicitly contains splitting ema! + // FIXME: search_ema_range implicitly contains splitting ema let range = self.search_ema_range(addr, addr + size, typ, false); match range { // exist in emas list - Ok(_) => { - // TODO: realloc EMA from reserve - match self.clear_reserved_emas(addr, addr + size, typ, alloc) { - Ok(ema) => { - alloc_addr = Some(addr); - alloc_next_ema = Some(ema); - } - Err(_) => { - if is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); - } + Ok(_) => match self.clear_reserved_emas(addr, addr + size, typ, alloc) { + Ok(ema) => { + alloc_addr = Some(addr); + alloc_next_ema = Some(ema); + } + Err(_) => { + if is_fixed_alloc { + return Err(SgxStatus::InvalidParameter); } } - } + }, // not exist in emas list Err(_) => { let next_ema = self.find_free_region_at(addr, size, typ); @@ -515,7 +360,6 @@ impl RangeManage { while count != 0 { let ema = cursor.get().unwrap(); ema.modify_perm_check()?; - // cursor.get().unwrap().modify_perm_check()?; cursor.move_next(); count -= 1; } @@ -608,9 +452,6 @@ impl RangeManage { let mut end_ema_ptr = curr_ema as *const EMA; - // Found the overlapping emas with range [start, end) - // needs to splitting emas - // Spliting start ema let mut start_cursor = match typ { RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, diff --git a/sgx_trts/src/edmm/tcs.rs b/sgx_trts/src/emm/tcs.rs similarity index 98% rename from sgx_trts/src/edmm/tcs.rs rename to sgx_trts/src/emm/tcs.rs index 1a820fc13..27aee3733 100644 --- a/sgx_trts/src/edmm/tcs.rs +++ b/sgx_trts/src/emm/tcs.rs @@ -63,7 +63,7 @@ pub fn mktcs(mk_tcs: NonNull) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] mod hw { use crate::arch::{self, Layout, Tcs}; - use crate::edmm::epc::PageType; + use crate::emm::page::PageType; use crate::emm::range::{RangeType, RM}; use crate::enclave::MmLayout; use crate::tcs::list; @@ -72,7 +72,7 @@ mod hw { use sgx_types::error::{SgxResult, SgxStatus}; pub fn add_tcs(mut tcs: NonNull) -> SgxResult { - use crate::edmm::layout::LayoutTable; + use crate::emm::layout::LayoutTable; let base = MmLayout::image_base(); let table = LayoutTable::new(); diff --git a/sgx_trts/src/edmm/trim.rs b/sgx_trts/src/emm/trim.rs similarity index 100% rename from sgx_trts/src/edmm/trim.rs rename to sgx_trts/src/emm/trim.rs diff --git a/sgx_trts/src/emm/user.rs b/sgx_trts/src/emm/user.rs deleted file mode 100644 index c65a40716..000000000 --- a/sgx_trts/src/emm/user.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License.. - -use crate::enclave::MmLayout; -pub fn is_within_rts_range(start: usize, len: usize) -> bool { - let end = if len > 0 { - if let Some(end) = start.checked_add(len - 1) { - end - } else { - return false; - } - } else { - start - }; - - let user_base = MmLayout::user_region_mem_base(); - let user_end = user_base + MmLayout::user_region_mem_size(); - - (start <= end) && ((start >= user_end) || (end < user_base)) -} - -pub fn is_within_user_range(start: usize, len: usize) -> bool { - let end = if len > 0 { - if let Some(end) = start.checked_add(len - 1) { - end - } else { - return false; - } - } else { - start - }; - - let user_base = MmLayout::user_region_mem_base(); - let user_end = user_base + MmLayout::user_region_mem_size(); - - (start <= end) && (start >= user_base) && (end < user_end) -} diff --git a/sgx_trts/src/enclave/entry.rs b/sgx_trts/src/enclave/entry.rs index 3bf7cac59..798d495cc 100644 --- a/sgx_trts/src/enclave/entry.rs +++ b/sgx_trts/src/enclave/entry.rs @@ -18,8 +18,8 @@ use crate::arch::Tcs; use crate::call; use crate::call::ECallIndex; -use crate::edmm::tcs; -use crate::edmm::tcs::MkTcs; +use crate::emm::tcs; +use crate::emm::tcs::MkTcs; use crate::enclave; use crate::enclave::state::{self, State}; use crate::tcs::tc; diff --git a/sgx_trts/src/enclave/mem.rs b/sgx_trts/src/enclave/mem.rs index bed5bf3c2..8d922810a 100644 --- a/sgx_trts/src/enclave/mem.rs +++ b/sgx_trts/src/enclave/mem.rs @@ -406,6 +406,40 @@ impl UserRegionMem { } } +pub fn is_within_rts_range(start: usize, len: usize) -> bool { + let end = if len > 0 { + if let Some(end) = start.checked_add(len - 1) { + end + } else { + return false; + } + } else { + start + }; + + let user_base = MmLayout::user_region_mem_base(); + let user_end = user_base + MmLayout::user_region_mem_size(); + + (start <= end) && ((start >= user_end) || (end < user_base)) +} + +pub fn is_within_user_range(start: usize, len: usize) -> bool { + let end = if len > 0 { + if let Some(end) = start.checked_add(len - 1) { + end + } else { + return false; + } + } else { + start + }; + + let user_base = MmLayout::user_region_mem_base(); + let user_end = user_base + MmLayout::user_region_mem_size(); + + (start <= end) && (start >= user_base) && (end < user_end) +} + pub fn is_within_enclave(p: *const u8, len: usize) -> bool { let start = p as usize; let end = if len > 0 { diff --git a/sgx_trts/src/enclave/mod.rs b/sgx_trts/src/enclave/mod.rs index afaa2b064..3c32a5cac 100644 --- a/sgx_trts/src/enclave/mod.rs +++ b/sgx_trts/src/enclave/mod.rs @@ -26,5 +26,8 @@ pub mod state; pub use atexit::{at_exit, cleanup}; pub use init::{ctors, global_init, rtinit}; -pub use mem::{is_within_enclave, is_within_host, EnclaveRange, MmLayout}; +pub use mem::{ + is_within_enclave, is_within_host, is_within_rts_range, is_within_user_range, EnclaveRange, + MmLayout, +}; pub use uninit::{global_exit, rtuninit, UNINIT_FLAG}; diff --git a/sgx_trts/src/enclave/uninit.rs b/sgx_trts/src/enclave/uninit.rs index 634a4832e..23f4ffb38 100644 --- a/sgx_trts/src/enclave/uninit.rs +++ b/sgx_trts/src/enclave/uninit.rs @@ -63,7 +63,7 @@ pub fn rtuninit(tc: ThreadControl) -> SgxResult { let is_legal = tc.is_init(); } else { use crate::feature::SysFeatures; - use crate::edmm::layout::LayoutTable; + use crate::emm::layout::LayoutTable; let is_legal = if SysFeatures::get().is_edmm() { tc.is_utility() || !LayoutTable::new().is_dyn_tcs_exist() @@ -81,10 +81,6 @@ pub fn rtuninit(tc: ThreadControl) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] { - // if SysFeatures::get().is_edmm() && edmm::tcs::accept_trim_tcs(tcs).is_err() { - // state::set_state(State::Crashed); - // bail!(SgxStatus::Unexpected); - // } if SysFeatures::get().is_edmm() { let mut range_manage = RM.get().unwrap().lock(); diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs index 5071f0a76..184bf2a59 100644 --- a/sgx_trts/src/lib.rs +++ b/sgx_trts/src/lib.rs @@ -65,7 +65,6 @@ mod version; mod xsave; pub mod capi; -pub mod edmm; pub mod emm; #[cfg(not(any(feature = "sim", feature = "hyper")))] diff --git a/sgx_trts/src/tcs/tc.rs b/sgx_trts/src/tcs/tc.rs index ecad2020d..fcd81b783 100644 --- a/sgx_trts/src/tcs/tc.rs +++ b/sgx_trts/src/tcs/tc.rs @@ -207,7 +207,7 @@ impl<'a> ThreadControl<'a> { #[cfg(not(any(feature = "sim", feature = "hyper")))] fn is_dyn_tcs(&self) -> bool { - let table = crate::edmm::layout::LayoutTable::new(); + let table = crate::emm::layout::LayoutTable::new(); if let Some(attr) = table.check_dyn_range(self.tcs() as *const Tcs as usize, 1, None) { if attr.flags == arch::SI_FLAGS_TCS { return true; @@ -307,5 +307,5 @@ pub fn get_stack_guard() -> NonZeroUsize { #[cfg(not(any(feature = "sim", feature = "hyper")))] fn stack_max_page() -> usize { - crate::edmm::layout::LayoutTable::new().dyn_stack_max_page() + crate::emm::layout::LayoutTable::new().dyn_stack_max_page() } diff --git a/sgx_trts/src/veh/exception.rs b/sgx_trts/src/veh/exception.rs index 220567125..b290d8991 100644 --- a/sgx_trts/src/veh/exception.rs +++ b/sgx_trts/src/veh/exception.rs @@ -16,7 +16,7 @@ // under the License.. use crate::arch::{self, MiscExInfo, SsaGpr, Tcs, Tds}; -use crate::edmm; +use crate::emm; use crate::emm::pfhandler::{mm_enclave_pfhandler, PfInfo}; use crate::enclave::state::{self, State}; use crate::error; @@ -139,7 +139,7 @@ pub fn handle(tcs: &mut Tcs) -> SgxResult { if (tds.stack_commit > page_aligned_delta) && ((tds.stack_commit - page_aligned_delta) >= tds.stack_limit) { - result = edmm::mem::expand_stack_epc_pages( + result = emm::init::expand_stack_epc_pages( tds.stack_commit - page_aligned_delta, page_aligned_delta >> arch::SE_PAGE_SHIFT, ) From a6f2eff8b80ad460ac199d912a977cfc7a5b4755 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Mon, 18 Sep 2023 17:06:20 +0800 Subject: [PATCH 09/20] Change EMM error handlers to OsResult --- sgx_trts/src/capi.rs | 2 +- sgx_trts/src/emm/alloc.rs | 19 ++--- sgx_trts/src/emm/bitmap.rs | 18 ++--- sgx_trts/src/emm/ema.rs | 79 +++++++++++--------- sgx_trts/src/emm/init.rs | 132 +++++++++++++++++++-------------- sgx_trts/src/emm/ocall.rs | 2 +- sgx_trts/src/emm/page.rs | 43 ++++++----- sgx_trts/src/emm/pfhandler.rs | 6 +- sgx_trts/src/emm/range.rs | 133 +++++++++++++++++++--------------- 9 files changed, 240 insertions(+), 194 deletions(-) diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs index 2855b2e53..d9ec21bc0 100644 --- a/sgx_trts/src/capi.rs +++ b/sgx_trts/src/capi.rs @@ -287,7 +287,7 @@ pub unsafe extern "C" fn sgx_mm_alloc( *out_addr = base as *mut u8; 0 } - Err(err) => err.into(), + Err(err) => err as u32, } } diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index b54533ed4..210ca3a39 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -20,6 +20,7 @@ use intrusive_collections::intrusive_adapter; use intrusive_collections::singly_linked_list::CursorMut; use intrusive_collections::singly_linked_list::{Link, SinglyLinkedList}; use intrusive_collections::UnsafeRef; +use sgx_tlibc_sys::ENOMEM; use core::alloc::{AllocError, Allocator, Layout}; use core::mem::size_of; @@ -31,7 +32,7 @@ use spin::{Mutex, Once}; use super::page::AllocFlags; use super::range::{RangeType, RM}; use super::{PageInfo, PageType, ProtFlags}; -use sgx_types::error::{SgxResult, SgxStatus}; +use sgx_types::error::OsResult; // The size of fixed static memory for Static Allocator const STATIC_MEM_SIZE: usize = 65536; @@ -368,7 +369,7 @@ impl Reserve { } /// Malloc memory - pub fn emalloc(&mut self, size: usize) -> SgxResult { + pub fn emalloc(&mut self, size: usize) -> OsResult { let mut bsize = round_to!(size + HEADER_SIZE, EXACT_MATCH_INCREMENT); bsize = bsize.max(MIN_BLOCK_SIZE); @@ -389,7 +390,7 @@ impl Reserve { block = self.alloc_from_chunks(bsize); // Should never happen if block.is_none() { - return Err(SgxStatus::InvalidParameter); + return Err(ENOMEM); } } @@ -429,7 +430,7 @@ impl Reserve { let block_size = block.block_size(); let block_end = block_addr + block_size; let res = self.find_chunk_with_block(block_addr, block_size); - if res.is_err() { + if res.is_none() { panic!(); } @@ -450,7 +451,7 @@ impl Reserve { /// Adding the size of interior memory /// rsize: memory increment - pub unsafe fn add_chunks(&mut self, rsize: usize) -> SgxResult { + pub unsafe fn add_chunks(&mut self, rsize: usize) -> OsResult { // Here we alloc at least INIT_MEM_SIZE size, // but commit rsize memory, the remaining memory is COMMIT_ON_DEMAND let increment = self.incr_size.max(rsize); @@ -516,9 +517,9 @@ impl Reserve { &mut self, block_addr: usize, block_size: usize, - ) -> SgxResult> { + ) -> Option> { if block_size == 0 { - return Err(SgxStatus::InvalidParameter); + return None; } let mut cursor = self.chunks.front_mut(); while !cursor.is_null() { @@ -526,11 +527,11 @@ impl Reserve { if (block_addr >= chunk.base) && ((block_addr + block_size) <= (chunk.base + chunk.used)) { - return Ok(cursor); + return Some(cursor); } cursor.move_next(); } - Err(SgxStatus::InvalidParameter) + None } } diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index dec63dbe4..d215e5180 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -20,8 +20,8 @@ use alloc::vec; use core::alloc::Allocator; use core::alloc::Layout; use core::ptr::NonNull; -use sgx_types::error::SgxResult; -use sgx_types::error::SgxStatus; +use sgx_tlibc_sys::EACCES; +use sgx_types::error::OsResult; use super::alloc::Alloc; use super::alloc::ResAlloc; @@ -38,7 +38,7 @@ pub struct BitArray { impl BitArray { /// Init BitArray with all zero bits - pub fn new(bits: usize, alloc: Alloc) -> SgxResult { + pub fn new(bits: usize, alloc: Alloc) -> OsResult { let bytes = (bits + 7) / 8; // FIXME: return error if OOM @@ -63,9 +63,9 @@ impl BitArray { } /// Get the value of the bit at a given index - pub fn get(&self, index: usize) -> SgxResult { + pub fn get(&self, index: usize) -> OsResult { if index >= self.bits { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } let byte_index = index / 8; @@ -86,9 +86,9 @@ impl BitArray { } /// Set the value of the bit at the specified index - pub fn set(&mut self, index: usize, value: bool) -> SgxResult { + pub fn set(&mut self, index: usize, value: bool) -> OsResult { if index >= self.bits { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } let byte_index = index / 8; let bit_index = index % 8; @@ -119,8 +119,8 @@ impl BitArray { /// Split current bit array at specified position, return a new allocated bit array /// corresponding to the bits at the range of [pos, end). /// And the current bit array manages the bits at the range of [0, pos). - pub fn split(&mut self, pos: usize) -> SgxResult { - ensure!(pos > 0 && pos < self.bits, SgxStatus::InvalidParameter); + pub fn split(&mut self, pos: usize) -> OsResult { + assert!(pos > 0 && pos < self.bits); let byte_index = pos / 8; let bit_index = pos % 8; diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index c68016a56..216e72c6e 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -20,7 +20,8 @@ use crate::emm::{PageInfo, PageRange, PageType, ProtFlags}; use crate::enclave::is_within_enclave; use alloc::boxed::Box; use intrusive_collections::{intrusive_adapter, LinkedListLink, UnsafeRef}; -use sgx_types::error::{SgxResult, SgxStatus}; +use sgx_tlibc_sys::{EACCES, EFAULT, EINVAL}; +use sgx_types::error::OsResult; use super::alloc::Alloc; use super::alloc::{ResAlloc, StaticAlloc}; @@ -65,7 +66,7 @@ impl EMA { handler: Option, priv_data: Option<*mut PfInfo>, alloc: Alloc, - ) -> SgxResult { + ) -> OsResult { // check alloc flags' eligibility // AllocFlags::try_from(alloc_flags.bits())?; @@ -87,14 +88,14 @@ impl EMA { alloc, }) } else { - Err(SgxStatus::InvalidParameter) + Err(EINVAL) } } /// Split current ema at specified address, return a new allocated ema /// corresponding to the memory at the range of [addr, end). /// And the current ema manages the memory at the range of [start, addr). - pub fn split(&mut self, addr: usize) -> SgxResult<*mut EMA> { + pub fn split(&mut self, addr: usize) -> OsResult<*mut EMA> { let l_start = self.start; let l_length = addr - l_start; @@ -158,7 +159,7 @@ impl EMA { } /// Allocate the reserve / committed / virtual memory at corresponding memory - pub fn alloc(&mut self) -> SgxResult { + pub fn alloc(&mut self) -> OsResult { // RESERVED region only occupy memory range, but no real allocation if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); @@ -180,7 +181,8 @@ impl EMA { }; // Ocall to mmap memory in urts - ocall::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags)?; + ocall::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags) + .map_err(|_| EFAULT)?; // Set the corresponding bits of eaccept map if self.alloc_flags.contains(AllocFlags::COMMIT_NOW) { @@ -194,7 +196,7 @@ impl EMA { } /// Eaccept target EPC pages with cpu instruction - fn eaccept(&self, start: usize, length: usize, grow_up: bool) -> SgxResult { + fn eaccept(&self, start: usize, length: usize, grow_up: bool) -> OsResult { let info = PageInfo { typ: self.info.typ, prot: self.info.prot | ProtFlags::PENDING, @@ -210,35 +212,35 @@ impl EMA { } /// Check the prerequisites of ema commitment - pub fn commit_check(&self) -> SgxResult { + pub fn commit_check(&self) -> OsResult { if !self.info.prot.intersects(ProtFlags::R | ProtFlags::W) { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } if self.info.typ != PageType::Reg { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } if self.alloc_flags.contains(AllocFlags::RESERVED) { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } Ok(()) } /// Commit the corresponding memory of this ema - pub fn commit_self(&mut self) -> SgxResult { + pub fn commit_self(&mut self) -> OsResult { self.commit(self.start, self.length) } /// Commit the partial memory of this ema - pub fn commit(&mut self, start: usize, length: usize) -> SgxResult { + pub fn commit(&mut self, start: usize, length: usize) -> OsResult { ensure!( length != 0 && (length % crate::arch::SE_PAGE_SIZE) == 0 && start >= self.start && start + length <= self.start + self.length, - SgxStatus::InvalidParameter + EINVAL ); let info = PageInfo { @@ -265,15 +267,15 @@ impl EMA { } /// Check the prerequisites of ema uncommitment - pub fn uncommit_check(&self) -> SgxResult { + pub fn uncommit_check(&self) -> OsResult { if self.alloc_flags.contains(AllocFlags::RESERVED) { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } Ok(()) } /// Uncommit the corresponding memory of this ema - pub fn uncommit_self(&mut self) -> SgxResult { + pub fn uncommit_self(&mut self) -> OsResult { let prot = self.info.prot; if prot == ProtFlags::NONE { self.modify_perm(ProtFlags::R)? @@ -283,8 +285,8 @@ impl EMA { } /// Uncommit the partial memory of this ema - pub fn uncommit(&mut self, start: usize, length: usize, prot: ProtFlags) -> SgxResult { - ensure!(self.eaccept_map.is_some(), SgxStatus::InvalidParameter); + pub fn uncommit(&mut self, start: usize, length: usize, prot: ProtFlags) -> OsResult { + assert!(self.eaccept_map.is_some()); if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); @@ -336,7 +338,8 @@ impl EMA { typ: PageType::Trim, prot, }, - )?; + ) + .map_err(|_| EFAULT)?; let pages = PageRange::new( block_start, @@ -363,30 +366,31 @@ impl EMA { typ: PageType::Trim, prot, }, - )?; + ) + .map_err(|_| EFAULT)?; start = block_end; } Ok(()) } /// Check the prerequisites of modifying permissions - pub fn modify_perm_check(&self) -> SgxResult { + pub fn modify_perm_check(&self) -> OsResult { if self.info.typ != PageType::Reg { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } if self.alloc_flags.contains(AllocFlags::RESERVED) { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } match &self.eaccept_map { Some(bitmap) => { if !bitmap.all_true() { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } } None => { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } } @@ -394,7 +398,7 @@ impl EMA { } /// Modifying the permissions of corresponding memory of this ema - pub fn modify_perm(&mut self, new_prot: ProtFlags) -> SgxResult { + pub fn modify_perm(&mut self, new_prot: ProtFlags) -> OsResult { if self.info.prot == new_prot { return Ok(()); } @@ -408,7 +412,8 @@ impl EMA { typ: self.info.typ, prot: new_prot, }, - )?; + ) + .map_err(|_| EFAULT)?; let info = PageInfo { typ: PageType::Reg, @@ -446,22 +451,23 @@ impl EMA { typ: self.info.typ, prot: ProtFlags::NONE, }, - )?; + ) + .map_err(|_| EFAULT)?; } Ok(()) } /// Changing the page type from Reg to Tcs - pub fn change_to_tcs(&mut self) -> SgxResult { + pub fn change_to_tcs(&mut self) -> OsResult { // The ema must have and only have one page if self.length != SE_PAGE_SIZE { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } // The page must be committed if !self.is_page_committed(self.start) { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } let info = self.info; @@ -470,7 +476,7 @@ impl EMA { } if (info.prot != (ProtFlags::R | ProtFlags::W)) || (info.typ != PageType::Reg) { - return Err(SgxStatus::InvalidParameter); + return Err(EACCES); } ocall::modify_ocall( @@ -481,7 +487,8 @@ impl EMA { typ: PageType::Tcs, prot: info.prot, }, - )?; + ) + .map_err(|_| EFAULT)?; let eaccept_info = PageInfo { typ: PageType::Tcs, @@ -515,7 +522,7 @@ impl EMA { } /// Deallocate the corresponding memory of this ema - pub fn dealloc(&mut self) -> SgxResult { + pub fn dealloc(&mut self) -> OsResult { if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); } @@ -563,7 +570,7 @@ impl EMA { (addr >= self.start) && (addr < self.start + self.length) } - pub fn set_eaccept_map_full(&mut self) -> SgxResult { + pub fn set_eaccept_map_full(&mut self) -> OsResult { if self.eaccept_map.is_none() { let mut eaccept_map = match self.alloc { Alloc::Reserve => { diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs index 743c0700a..aea2d0d93 100644 --- a/sgx_trts/src/emm/init.rs +++ b/sgx_trts/src/emm/init.rs @@ -88,17 +88,19 @@ mod hw { // entry is guard page or has EREMOVE, build a reserved ema if (entry.si_flags == 0) || (entry.attributes & arch::PAGE_ATTR_EREMOVE != 0) { - range_manage.init_static_region( - addr, - size, - AllocFlags::RESERVED | AllocFlags::SYSTEM, - PageInfo { - typ: PageType::None, - prot: ProtFlags::NONE, - }, - None, - None, - )?; + range_manage + .init_static_region( + addr, + size, + AllocFlags::RESERVED | AllocFlags::SYSTEM, + PageInfo { + typ: PageType::None, + prot: ProtFlags::NONE, + }, + None, + None, + ) + .map_err(|_| SgxStatus::Unexpected)?; return Ok(()); } @@ -108,19 +110,23 @@ mod hw { if post_remove { // TODO: maybe AllocFlags need more flags or PageType is not None - range_manage.init_static_region( - addr, - size, - AllocFlags::SYSTEM, - PageInfo { - typ: PageType::None, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - )?; - - range_manage.dealloc(addr, size, RangeType::Rts)?; + range_manage + .init_static_region( + addr, + size, + AllocFlags::SYSTEM, + PageInfo { + typ: PageType::None, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ) + .map_err(|_| SgxStatus::Unexpected)?; + + range_manage + .dealloc(addr, size, RangeType::Rts) + .map_err(|_| SgxStatus::Unexpected)?; } if post_add { @@ -134,22 +140,24 @@ mod hw { }; // TODO: revise alloc and not use int - range_manage.alloc( - Some(addr), - size, - AllocFlags::COMMIT_ON_DEMAND - | commit_direction - | AllocFlags::SYSTEM - | AllocFlags::FIXED, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - RangeType::Rts, - Alloc::Reserve, - )?; + range_manage + .alloc( + Some(addr), + size, + AllocFlags::COMMIT_ON_DEMAND + | commit_direction + | AllocFlags::SYSTEM + | AllocFlags::FIXED, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + RangeType::Rts, + Alloc::Reserve, + ) + .map_err(|_| SgxStatus::Unexpected)?; } else if static_min { let info = if entry.id == arch::LAYOUT_ID_TCS { PageInfo { @@ -164,7 +172,9 @@ mod hw { ), } }; - range_manage.init_static_region(addr, size, AllocFlags::SYSTEM, info, None, None)?; + range_manage + .init_static_region(addr, size, AllocFlags::SYSTEM, info, None, None) + .map_err(|_| SgxStatus::Unexpected)?; } Ok(()) @@ -178,7 +188,9 @@ mod hw { .ok_or(SgxStatus::InvalidParameter)?; let mut range_manage = RM.get().unwrap().lock(); - range_manage.commit(addr, count << arch::SE_PAGE_SHIFT, RangeType::Rts)?; + range_manage + .commit(addr, count << arch::SE_PAGE_SHIFT, RangeType::Rts) + .map_err(|_| SgxStatus::Unexpected)?; Ok(()) } @@ -206,7 +218,9 @@ mod hw { } let prot = ProtFlags::from_bits_truncate(perm as u8); - range_manage.modify_perms(start, size, prot, RangeType::Rts)?; + range_manage + .modify_perms(start, size, prot, RangeType::Rts) + .map_err(|_| SgxStatus::Unexpected)?; } if typ == Type::GnuRelro { let start = base + trim_to_page!(phdr.virtual_addr() as usize); @@ -215,7 +229,9 @@ mod hw { let size = end - start; if size > 0 { - range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; + range_manage + .modify_perms(start, size, ProtFlags::R, RangeType::Rts) + .map_err(|_| SgxStatus::Unexpected)?; } } } @@ -229,7 +245,9 @@ mod hw { let start = base + unsafe { layout.entry.rva as usize }; let size = unsafe { layout.entry.page_count as usize } << arch::SE_PAGE_SHIFT; - range_manage.modify_perms(start, size, ProtFlags::R, RangeType::Rts)?; + range_manage + .modify_perms(start, size, ProtFlags::R, RangeType::Rts) + .map_err(|_| SgxStatus::Unexpected)?; } Ok(()) } @@ -256,17 +274,19 @@ mod hw { } let mut range_manage = RM.get().unwrap().lock(); - range_manage.init_static_region( - start, - end - start, - AllocFlags::SYSTEM, - PageInfo { - typ: PageType::Reg, - prot: perm, - }, - None, - None, - )?; + range_manage + .init_static_region( + start, + end - start, + AllocFlags::SYSTEM, + PageInfo { + typ: PageType::Reg, + prot: perm, + }, + None, + None, + ) + .map_err(|_| SgxStatus::Unexpected)?; } } diff --git a/sgx_trts/src/emm/ocall.rs b/sgx_trts/src/emm/ocall.rs index 932cdd010..8346b130e 100644 --- a/sgx_trts/src/emm/ocall.rs +++ b/sgx_trts/src/emm/ocall.rs @@ -134,7 +134,7 @@ mod hw { #[cfg(any(feature = "sim", feature = "hyper"))] mod sw { - use sgx_types::error::SgxResult; + use sgx_types::error::OsResult; use sgx_types::types::ProtectPerm; #[allow(clippy::unnecessary_wraps)] diff --git a/sgx_trts/src/emm/page.rs b/sgx_trts/src/emm/page.rs index a74eeb0cc..3e826fe62 100644 --- a/sgx_trts/src/emm/page.rs +++ b/sgx_trts/src/emm/page.rs @@ -22,7 +22,8 @@ use crate::enclave::is_within_enclave; use crate::inst::EncluInst; use bitflags::bitflags; use core::num::NonZeroUsize; -use sgx_types::error::{SgxResult, SgxStatus}; +use sgx_tlibc_sys::{EFAULT, EINVAL}; +use sgx_types::error::{OsResult, SgxResult, SgxStatus}; use sgx_types::marker::ContiguousMemory; bitflags! { @@ -91,7 +92,7 @@ pub struct PageRange { unsafe impl ContiguousMemory for PageRange {} impl PageRange { - pub fn new(addr: usize, count: usize, info: PageInfo) -> SgxResult { + pub fn new(addr: usize, count: usize, info: PageInfo) -> OsResult { if addr != 0 && count != 0 && is_within_enclave(addr as *const u8, count * SE_PAGE_SIZE) @@ -103,32 +104,32 @@ impl PageRange { info, }) } else { - Err(SgxStatus::InvalidParameter) + Err(EINVAL) } } - pub fn accept_forward(&self) -> SgxResult { + pub fn accept_forward(&self) -> OsResult { for page in self.iter() { page.accept()?; } Ok(()) } - pub fn accept_backward(&self) -> SgxResult { + pub fn accept_backward(&self) -> OsResult { for page in self.iter().rev() { page.accept()?; } Ok(()) } - pub fn modpe(&self) -> SgxResult { + pub fn modpe(&self) -> OsResult { for page in self.iter() { page.modpe()?; } Ok(()) } - pub(crate) fn modify(&self) -> SgxResult { + pub(crate) fn modify(&self) -> OsResult { for page in self.iter() { let _ = page.modpe(); if !page.info.prot.contains(ProtFlags::W | ProtFlags::X) { @@ -214,12 +215,12 @@ pub struct Page { unsafe impl ContiguousMemory for Page {} impl Page { - pub fn new(addr: usize, info: PageInfo) -> SgxResult { + pub fn new(addr: usize, info: PageInfo) -> OsResult { ensure!( addr != 0 && is_within_enclave(addr as *const u8, SE_PAGE_SIZE) && is_page_aligned!(addr), - SgxStatus::InvalidParameter + EINVAL ); Ok(Page { addr, info }) } @@ -228,14 +229,14 @@ impl Page { Page { addr, info } } - pub fn accept(&self) -> SgxResult { - let secinfo: SecInfo = self.info.into(); - EncluInst::eaccept(&secinfo, self.addr).map_err(|_| SgxStatus::Unexpected) + pub fn accept(&self) -> OsResult { + let secinfo: Secinfo = self.info.into(); + EncluInst::eaccept(&secinfo, self.addr).map_err(|_| EFAULT) } - pub fn modpe(&self) -> SgxResult { - let secinfo: SecInfo = self.info.into(); - EncluInst::emodpe(&secinfo, self.addr).map_err(|_| SgxStatus::Unexpected) + pub fn modpe(&self) -> OsResult { + let secinfo: Secinfo = self.info.into(); + EncluInst::emodpe(&secinfo, self.addr).map_err(|_| EFAULT) } } @@ -250,11 +251,12 @@ pub fn apply_epc_pages(addr: usize, count: usize) -> SgxResult { typ: PageType::Reg, prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, }, - )?; + ) + .map_err(|_| SgxStatus::Unexpected)?; if (attr.attr & arch::PAGE_DIR_GROW_DOWN) == 0 { - pages.accept_forward() + pages.accept_forward().map_err(|_| SgxStatus::Unexpected) } else { - pages.accept_backward() + pages.accept_backward().map_err(|_| SgxStatus::Unexpected) } } else { Err(SgxStatus::InvalidParameter) @@ -277,8 +279,9 @@ pub fn trim_epc_pages(addr: usize, count: usize) -> SgxResult { typ: PageType::Trim, prot: ProtFlags::MODIFIED, }, - )?; - pages.accept_forward()?; + ) + .map_err(|_| SgxStatus::Unexpected)?; + pages.accept_forward().map_err(|_| SgxStatus::Unexpected)?; trim::trim_range_commit(addr, count)?; diff --git a/sgx_trts/src/emm/pfhandler.rs b/sgx_trts/src/emm/pfhandler.rs index a6360251f..ad81fc2cd 100644 --- a/sgx_trts/src/emm/pfhandler.rs +++ b/sgx_trts/src/emm/pfhandler.rs @@ -89,14 +89,14 @@ pub extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { let addr = trim_to_page!(info.maddr as usize); let mut range_manage = RM.get().unwrap().lock(); let mut ema_cursor = match range_manage.search_ema(addr, RangeType::User) { - Err(_) => { + None => { let ema_cursor = range_manage.search_ema(addr, RangeType::Rts); - if ema_cursor.is_err() { + if ema_cursor.is_none() { return HandleResult::Search; } ema_cursor.unwrap() } - Ok(ema_cursor) => ema_cursor, + Some(ema_cursor) => ema_cursor, }; let ema = unsafe { ema_cursor.get_mut().unwrap() }; diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index 14020efb8..1c902923d 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -23,7 +23,8 @@ use crate::{ }; use alloc::boxed::Box; use intrusive_collections::{linked_list::CursorMut, LinkedList, UnsafeRef}; -use sgx_types::error::{SgxResult, SgxStatus}; +use sgx_tlibc_sys::{EEXIST, EINVAL, ENOMEM, EPERM}; +use sgx_types::error::OsResult; use spin::Once; use super::{ @@ -83,13 +84,15 @@ impl RangeManage { info: PageInfo, handler: Option, priv_data: Option<*mut PfInfo>, - ) -> SgxResult { + ) -> OsResult { ensure!( addr != 0 && size != 0 && is_within_enclave(addr as *const u8, size), - SgxStatus::InvalidParameter + EINVAL ); - let mut next_ema = self.find_free_region_at(addr, size, RangeType::Rts)?; + let mut next_ema = self + .find_free_region_at(addr, size, RangeType::Rts) + .ok_or(EINVAL)?; let mut new_ema = Box::::new_in( EMA::new( @@ -122,7 +125,7 @@ impl RangeManage { end: usize, typ: RangeType, alloc: Alloc, - ) -> SgxResult> { + ) -> Option> { let (mut cursor, ema_num) = self.search_ema_range(start, end, typ, true)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; @@ -132,7 +135,7 @@ impl RangeManage { let ema = cursor.get().unwrap(); // EMA must be reserved and can not manage internal memory region if !ema.flags().contains(AllocFlags::RESERVED) || ema.allocator() != alloc { - return Err(SgxStatus::InvalidParameter); + return None; } cursor.move_next(); count -= 1; @@ -149,7 +152,7 @@ impl RangeManage { count -= 1; } - Ok(cursor) + Some(cursor) } /// Allocate a new memory region in enclave address space (ELRANGE). @@ -163,7 +166,7 @@ impl RangeManage { priv_data: Option<*mut PfInfo>, typ: RangeType, alloc: Alloc, - ) -> SgxResult { + ) -> OsResult { let addr = addr.unwrap_or(0); // Default align is 12 @@ -171,15 +174,15 @@ impl RangeManage { let align_mask: usize = (1 << align_flag) - 1; if (size % SE_PAGE_SIZE) > 0 { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } if (addr & align_mask) > 0 { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } if (addr > 0) && !is_within_enclave(addr as *const u8, size) { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } let mut alloc_addr: Option = None; @@ -192,29 +195,31 @@ impl RangeManage { match range { // exist in emas list - Ok(_) => match self.clear_reserved_emas(addr, addr + size, typ, alloc) { - Ok(ema) => { + Some(_) => match self.clear_reserved_emas(addr, addr + size, typ, alloc) { + Some(ema) => { alloc_addr = Some(addr); alloc_next_ema = Some(ema); } - Err(_) => { + None => { if is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); + return Err(EEXIST); } } }, // not exist in emas list - Err(_) => { + None => { let next_ema = self.find_free_region_at(addr, size, typ); - if next_ema.is_err() && is_fixed_alloc { - return Err(SgxStatus::InvalidParameter); + if next_ema.is_none() && is_fixed_alloc { + return Err(EPERM); } } }; }; if alloc_addr.is_none() { - let (free_addr, next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; + let (free_addr, next_ema) = self + .find_free_region(size, 1 << align_flag, typ) + .ok_or(ENOMEM)?; alloc_addr = Some(free_addr); alloc_next_ema = Some(next_ema); } @@ -264,8 +269,10 @@ impl RangeManage { /// Commit a partial or full range of memory allocated previously with /// COMMIT_ON_DEMAND. - pub fn commit(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { - let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; + pub fn commit(&mut self, addr: usize, size: usize, typ: RangeType) -> OsResult { + let (mut cursor, ema_num) = self + .search_ema_range(addr, addr + size, typ, true) + .ok_or(EINVAL)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; let mut count = ema_num; @@ -291,8 +298,10 @@ impl RangeManage { } /// Deallocate the address range. - pub fn dealloc(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { - let (mut cursor, mut ema_num) = self.search_ema_range(addr, addr + size, typ, false)?; + pub fn dealloc(&mut self, addr: usize, size: usize, typ: RangeType) -> OsResult { + let (mut cursor, mut ema_num) = self + .search_ema_range(addr, addr + size, typ, false) + .ok_or(EINVAL)?; while ema_num != 0 { // Calling remove() implicitly moves cursor pointing to next ema let mut ema = cursor.remove().unwrap(); @@ -320,16 +329,18 @@ impl RangeManage { size: usize, new_page_typ: PageType, range_typ: RangeType, - ) -> SgxResult { + ) -> OsResult { if new_page_typ != PageType::Tcs { - return Err(SgxStatus::InvalidParameter); + return Err(EPERM); } if size != SE_PAGE_SIZE { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } - let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, range_typ, true)?; + let (mut cursor, ema_num) = self + .search_ema_range(addr, addr + size, range_typ, true) + .ok_or(EINVAL)?; assert!(ema_num == 1); unsafe { cursor.get_mut().unwrap().change_to_tcs()? }; @@ -343,17 +354,19 @@ impl RangeManage { size: usize, prot: ProtFlags, typ: RangeType, - ) -> SgxResult { + ) -> OsResult { ensure!( (size != 0) && (size % SE_PAGE_SIZE == 0) && (addr % SE_PAGE_SIZE == 0), - SgxStatus::InvalidParameter + EINVAL ); if prot.contains(ProtFlags::X) && !prot.contains(ProtFlags::R) { - return Err(SgxStatus::InvalidParameter); + return Err(EINVAL); } - let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; + let (mut cursor, ema_num) = self + .search_ema_range(addr, addr + size, typ, true) + .ok_or(EINVAL)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; let mut count = ema_num; @@ -380,8 +393,10 @@ impl RangeManage { } /// Uncommit (trim) physical EPC pages in a previously committed range. - pub fn uncommit(&mut self, addr: usize, size: usize, typ: RangeType) -> SgxResult { - let (mut cursor, ema_num) = self.search_ema_range(addr, addr + size, typ, true)?; + pub fn uncommit(&mut self, addr: usize, size: usize, typ: RangeType) -> OsResult { + let (mut cursor, ema_num) = self + .search_ema_range(addr, addr + size, typ, true) + .ok_or(EINVAL)?; let start_ema_ptr = cursor.get().unwrap() as *const EMA; let mut count = ema_num; @@ -417,7 +432,7 @@ impl RangeManage { end: usize, typ: RangeType, continuous: bool, - ) -> SgxResult<(CursorMut<'_, EmaAda>, usize)> { + ) -> Option<(CursorMut<'_, EmaAda>, usize)> { let mut cursor = match typ { RangeType::Rts => self.rts.front(), RangeType::User => self.user.front(), @@ -428,7 +443,7 @@ impl RangeManage { } if cursor.is_null() || cursor.get().unwrap().higher_than_addr(end) { - return Err(SgxStatus::InvalidParameter); + return None; } let mut curr_ema = cursor.get().unwrap(); @@ -442,7 +457,7 @@ impl RangeManage { // If continuity is required, there should // be no gaps in the specified range in the emas list. if continuous && prev_end != curr_ema.start() { - return Err(SgxStatus::InvalidParameter); + return None; } emas_num += 1; @@ -495,11 +510,11 @@ impl RangeManage { RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, }; - Ok((start_cursor, emas_num)) + Some((start_cursor, emas_num)) } // search for a ema node whose memory range contains address - pub fn search_ema(&mut self, addr: usize, typ: RangeType) -> SgxResult> { + pub fn search_ema(&mut self, addr: usize, typ: RangeType) -> Option> { let mut cursor = match typ { RangeType::Rts => self.rts.front_mut(), RangeType::User => self.user.front_mut(), @@ -508,12 +523,12 @@ impl RangeManage { while !cursor.is_null() { let ema = cursor.get().unwrap(); if ema.overlap_addr(addr) { - return Ok(cursor); + return Some(cursor); } cursor.move_next(); } - Err(SgxStatus::InvalidParameter) + None } // Find a free space at addr with 'len' bytes in reserve region, @@ -524,19 +539,19 @@ impl RangeManage { addr: usize, len: usize, typ: RangeType, - ) -> SgxResult> { + ) -> Option> { if !is_within_enclave(addr as *const u8, len) { - return Err(SgxStatus::InvalidParameter); + return None; } match typ { RangeType::Rts => { if !is_within_rts_range(addr, len) { - return Err(SgxStatus::InvalidParameter); + return None; } } RangeType::User => { if !is_within_user_range(addr, len) { - return Err(SgxStatus::InvalidParameter); + return None; } } } @@ -550,7 +565,7 @@ impl RangeManage { let start_curr = cursor.get().map(|ema| ema.start()).unwrap(); let end_curr = start_curr + cursor.get().map(|ema| ema.len()).unwrap(); if start_curr >= addr + len { - return Ok(cursor); + return Some(cursor); } if addr >= end_curr { @@ -562,10 +577,10 @@ impl RangeManage { // means addr is larger than the end of the last ema node if cursor.is_null() { - return Ok(cursor); + return Some(cursor); } - Err(SgxStatus::InvalidParameter) + None } // Find a free space of size at least 'size' bytes in reserve region, @@ -575,7 +590,7 @@ impl RangeManage { len: usize, align: usize, typ: RangeType, - ) -> SgxResult<(usize, CursorMut<'_, EmaAda>)> { + ) -> Option<(usize, CursorMut<'_, EmaAda>)> { let user_base = MmLayout::user_region_mem_base(); let user_end = user_base + MmLayout::user_region_mem_size(); @@ -593,23 +608,23 @@ impl RangeManage { if user_base >= len { addr = trim_to!(user_base - len, align); if is_within_enclave(addr as *const u8, len) { - return Ok((addr, cursor)); + return Some((addr, cursor)); } } else { addr = round_to!(user_end, align); // no integer overflow if addr + len >= addr && is_within_enclave(addr as *const u8, len) { - return Ok((addr, cursor)); + return Some((addr, cursor)); } } - return Err(SgxStatus::InvalidParameter); + return None; } RangeType::User => { addr = round_to!(user_base, align); if is_within_user_range(addr, len) { - return Ok((addr, cursor)); + return Some((addr, cursor)); } - return Err(SgxStatus::InvalidParameter); + return None; } } } @@ -628,7 +643,7 @@ impl RangeManage { && (typ == RangeType::User || is_within_rts_range(curr_end, len)) { cursor.move_next(); - return Ok((curr_end, cursor)); + return Some((curr_end, cursor)); } } cursor.move_next(); @@ -642,7 +657,7 @@ impl RangeManage { || (typ == RangeType::User && is_within_user_range(addr, len))) { cursor.move_next(); - return Ok((addr, cursor)); + return Some((addr, cursor)); } // Cursor moves to emas->front_mut. @@ -653,7 +668,7 @@ impl RangeManage { // Back to the first ema to check rts region before user region let start_first = cursor.get().map(|ema| ema.start()).unwrap(); if start_first < len { - return Err(SgxStatus::InvalidParameter); + return None; } addr = trim_to!(start_first, align); @@ -661,16 +676,16 @@ impl RangeManage { match typ { RangeType::User => { if is_within_user_range(addr, len) { - return Ok((addr, cursor)); + return Some((addr, cursor)); } } RangeType::Rts => { if is_within_enclave(addr as *const u8, len) && is_within_rts_range(addr, len) { - return Ok((addr, cursor)); + return Some((addr, cursor)); } } } - Err(SgxStatus::InvalidParameter) + None } } From 07ed3198dcf36e0daae95ed6df70abb33e25dea4 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 22 Sep 2023 09:55:29 +0800 Subject: [PATCH 10/20] Fix trivial bugs --- sgx_trts/src/emm/ema.rs | 22 +++------ sgx_trts/src/emm/mod.rs | 14 +++++- sgx_trts/src/emm/ocall.rs | 33 ++++++++----- sgx_trts/src/emm/pfhandler.rs | 16 +++--- sgx_trts/src/emm/range.rs | 92 +++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 34 deletions(-) diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index 216e72c6e..fa0a75d9f 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -181,8 +181,7 @@ impl EMA { }; // Ocall to mmap memory in urts - ocall::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags) - .map_err(|_| EFAULT)?; + ocall::alloc_ocall(self.start, self.length, self.info.typ, self.alloc_flags)?; // Set the corresponding bits of eaccept map if self.alloc_flags.contains(AllocFlags::COMMIT_NOW) { @@ -277,7 +276,7 @@ impl EMA { /// Uncommit the corresponding memory of this ema pub fn uncommit_self(&mut self) -> OsResult { let prot = self.info.prot; - if prot == ProtFlags::NONE { + if prot == ProtFlags::NONE && (self.info.typ != PageType::Tcs) { self.modify_perm(ProtFlags::R)? } @@ -338,8 +337,7 @@ impl EMA { typ: PageType::Trim, prot, }, - ) - .map_err(|_| EFAULT)?; + )?; let pages = PageRange::new( block_start, @@ -366,8 +364,7 @@ impl EMA { typ: PageType::Trim, prot, }, - ) - .map_err(|_| EFAULT)?; + )?; start = block_end; } Ok(()) @@ -412,8 +409,7 @@ impl EMA { typ: self.info.typ, prot: new_prot, }, - ) - .map_err(|_| EFAULT)?; + )?; let info = PageInfo { typ: PageType::Reg, @@ -451,8 +447,7 @@ impl EMA { typ: self.info.typ, prot: ProtFlags::NONE, }, - ) - .map_err(|_| EFAULT)?; + )?; } Ok(()) @@ -487,8 +482,7 @@ impl EMA { typ: PageType::Tcs, prot: info.prot, }, - ) - .map_err(|_| EFAULT)?; + )?; let eaccept_info = PageInfo { typ: PageType::Tcs, @@ -527,7 +521,7 @@ impl EMA { return Ok(()); } - if self.info.prot == ProtFlags::NONE { + if self.info.prot == ProtFlags::NONE && (self.info.typ != PageType::Tcs) { self.modify_perm(ProtFlags::R)?; } self.uncommit(self.start, self.length, ProtFlags::NONE)?; diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index 291df3c0d..0a01b2586 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -30,4 +30,16 @@ pub(crate) mod tcs; pub(crate) mod trim; pub use ocall::{modpr_ocall, mprotect_ocall}; -pub use page::{apply_epc_pages, trim_epc_pages, PageInfo, PageRange, PageType, ProtFlags}; +pub use page::{ + apply_epc_pages, trim_epc_pages, AllocFlags, PageInfo, PageRange, PageType, ProtFlags, +}; +pub use pfhandler::{PfHandler, PfInfo, Pfec, PfecBits}; + +pub use range::{ + rts_mm_alloc, rts_mm_commit, rts_mm_dealloc, rts_mm_modify_perms, rts_mm_modify_type, + rts_mm_uncommit, +}; +pub use range::{ + user_mm_alloc, user_mm_commit, user_mm_dealloc, user_mm_modify_perms, user_mm_modify_type, + user_mm_uncommit, +}; diff --git a/sgx_trts/src/emm/ocall.rs b/sgx_trts/src/emm/ocall.rs index 8346b130e..234d89395 100644 --- a/sgx_trts/src/emm/ocall.rs +++ b/sgx_trts/src/emm/ocall.rs @@ -31,7 +31,8 @@ mod hw { use crate::emm::{PageInfo, PageType}; use alloc::boxed::Box; use core::convert::Into; - use sgx_types::error::{SgxResult, SgxStatus}; + use sgx_tlibc_sys::EFAULT; + use sgx_types::error::{OsResult, SgxResult, SgxStatus}; use sgx_types::types::ProtectPerm; #[repr(C)] #[derive(Clone, Copy, Debug, Default)] @@ -48,7 +49,7 @@ mod hw { length: usize, page_type: PageType, alloc_flags: AllocFlags, - ) -> SgxResult { + ) -> OsResult { let mut change = Box::try_new_in( EmmAllocOcall { retval: 0, @@ -59,9 +60,14 @@ mod hw { }, OcAlloc, ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::Alloc, Some(change.as_mut())) + .map_err(|_| EFAULT)?; + + let ocall_ret = ocall(OCallIndex::Alloc, Some(change.as_mut())); + if ocall_ret == Ok(()) && change.retval == 0 { + Ok(()) + } else { + Err(EFAULT) + } } #[repr(C)] @@ -79,7 +85,7 @@ mod hw { length: usize, info_from: PageInfo, info_to: PageInfo, - ) -> SgxResult { + ) -> OsResult { let mut change = Box::try_new_in( EmmModifyOcall { retval: 0, @@ -90,9 +96,14 @@ mod hw { }, OcAlloc, ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::Modify, Some(change.as_mut())) + .map_err(|_| EFAULT)?; + + let ocall_ret = ocall(OCallIndex::Modify, Some(change.as_mut())); + if ocall_ret == Ok(()) && change.retval == 0 { + Ok(()) + } else { + Err(EFAULT) + } } #[repr(C)] @@ -144,7 +155,7 @@ mod sw { _length: usize, _page_type: PageType, _alloc_flags: AllocFlags, - ) -> SgxResult { + ) -> OsResult { Ok(()) } @@ -155,7 +166,7 @@ mod sw { _length: usize, _info_from: PageInfo, _info_to: PageInfo, - ) -> SgxResult { + ) -> OsResult { Ok(()) } diff --git a/sgx_trts/src/emm/pfhandler.rs b/sgx_trts/src/emm/pfhandler.rs index ad81fc2cd..cbebc2dc3 100644 --- a/sgx_trts/src/emm/pfhandler.rs +++ b/sgx_trts/src/emm/pfhandler.rs @@ -26,20 +26,20 @@ use crate::{ #[repr(C)] pub struct PfInfo { - maddr: u64, // address for #PF. - pfec: Pfec, - reserved: u32, + pub maddr: u64, // address for #PF. + pub pfec: Pfec, + pub reserved: u32, } #[repr(C)] -union Pfec { - errcd: u32, - bits: PfecBits, +pub union Pfec { + pub errcd: u32, + pub bits: PfecBits, } #[repr(C, packed)] #[derive(Clone, Copy, Debug)] -struct PfecBits(u32); +pub struct PfecBits(u32); impl PfecBits { const P_OFFSET: u32 = 0; @@ -129,7 +129,7 @@ pub extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { }; ema.commit_check() .expect("The EPC page fails to meet the commit condition."); - ema.commit(addr, addr + crate::arch::SE_PAGE_SIZE) + ema.commit(addr, crate::arch::SE_PAGE_SIZE) .expect("The EPC page fails to be committed."); HandleResult::Execution } else { diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index 1c902923d..b83115bc7 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -52,6 +52,98 @@ pub fn init_range_manage() { RM.call_once(|| SpinReentrantMutex::new(RangeManage::new())); } +pub fn user_mm_alloc( + addr: Option, + size: usize, + alloc_flags: AllocFlags, + info: PageInfo, + handler: Option, + priv_data: Option<*mut PfInfo>, +) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.alloc( + addr, + size, + alloc_flags, + info, + handler, + priv_data, + RangeType::User, + Alloc::Reserve, + ) +} + +pub fn user_mm_dealloc(addr: usize, size: usize) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.dealloc(addr, size, RangeType::User) +} + +pub fn user_mm_commit(addr: usize, size: usize) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.commit(addr, size, RangeType::User) +} + +pub fn user_mm_uncommit(addr: usize, size: usize) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.uncommit(addr, size, RangeType::User) +} + +pub fn user_mm_modify_type(addr: usize, size: usize, new_page_typ: PageType) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.modify_type(addr, size, new_page_typ, RangeType::User) +} + +pub fn user_mm_modify_perms(addr: usize, size: usize, prot: ProtFlags) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.modify_perms(addr, size, prot, RangeType::User) +} + +pub fn rts_mm_alloc( + addr: Option, + size: usize, + alloc_flags: AllocFlags, + info: PageInfo, + handler: Option, + priv_data: Option<*mut PfInfo>, +) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.alloc( + addr, + size, + alloc_flags, + info, + handler, + priv_data, + RangeType::Rts, + Alloc::Reserve, + ) +} + +pub fn rts_mm_dealloc(addr: usize, size: usize) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.dealloc(addr, size, RangeType::Rts) +} + +pub fn rts_mm_commit(addr: usize, size: usize) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.commit(addr, size, RangeType::Rts) +} + +pub fn rts_mm_uncommit(addr: usize, size: usize) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.uncommit(addr, size, RangeType::Rts) +} + +pub fn rts_mm_modify_type(addr: usize, size: usize, new_page_typ: PageType) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.modify_type(addr, size, new_page_typ, RangeType::Rts) +} + +pub fn rts_mm_modify_perms(addr: usize, size: usize, prot: ProtFlags) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.modify_perms(addr, size, prot, RangeType::Rts) +} + /// RangeManage manages virtual memory range pub struct RangeManage { user: LinkedList, From d7da52202efcbbd0b088ca6b832201124eb01b42 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 22 Sep 2023 09:58:41 +0800 Subject: [PATCH 11/20] Add new emm sample code --- samplecode/emm/Makefile | 203 +++++++++++++++ samplecode/emm/app/Cargo.toml | 30 +++ samplecode/emm/app/build.rs | 37 +++ samplecode/emm/app/src/main.rs | 51 ++++ samplecode/emm/enclave/Cargo.toml | 34 +++ samplecode/emm/enclave/Xargo.toml | 23 ++ samplecode/emm/enclave/config.xml | 38 +++ samplecode/emm/enclave/enclave.edl | 35 +++ samplecode/emm/enclave/enclave.lds | 12 + samplecode/emm/enclave/private.pem | 39 +++ samplecode/emm/enclave/src/lib.rs | 396 +++++++++++++++++++++++++++++ 11 files changed, 898 insertions(+) create mode 100644 samplecode/emm/Makefile create mode 100644 samplecode/emm/app/Cargo.toml create mode 100644 samplecode/emm/app/build.rs create mode 100644 samplecode/emm/app/src/main.rs create mode 100644 samplecode/emm/enclave/Cargo.toml create mode 100644 samplecode/emm/enclave/Xargo.toml create mode 100644 samplecode/emm/enclave/config.xml create mode 100644 samplecode/emm/enclave/enclave.edl create mode 100644 samplecode/emm/enclave/enclave.lds create mode 100644 samplecode/emm/enclave/private.pem create mode 100644 samplecode/emm/enclave/src/lib.rs diff --git a/samplecode/emm/Makefile b/samplecode/emm/Makefile new file mode 100644 index 000000000..f1a3e1189 --- /dev/null +++ b/samplecode/emm/Makefile @@ -0,0 +1,203 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +######## SGX SDK Settings ######## + +SGX_SDK ?= /opt/intel/sgxsdk +SGX_MODE ?= HW +SGX_ARCH ?= x64 + +TOP_DIR := ../.. +include $(TOP_DIR)/buildenv.mk + +ifeq ($(shell getconf LONG_BIT), 32) + SGX_ARCH := x86 +else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32) + SGX_ARCH := x86 +endif + +ifeq ($(SGX_ARCH), x86) + SGX_COMMON_CFLAGS := -m32 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib + SGX_BIN_PATH := $(SGX_SDK)/bin/x86 +else + SGX_COMMON_CFLAGS := -m64 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 + SGX_BIN_PATH := $(SGX_SDK)/bin/x64 +endif + +ifeq ($(SGX_DEBUG), 1) + SGX_COMMON_CFLAGS += -O0 -g + Rust_Build_Flags := + Rust_Build_Out := debug +else + SGX_COMMON_CFLAGS += -O2 + Rust_Build_Flags := --release + Rust_Build_Out := release +endif + +SGX_EDGER8R := $(SGX_BIN_PATH)/sgx_edger8r +ifneq ($(SGX_MODE), HYPER) + SGX_ENCLAVE_SIGNER := $(SGX_BIN_PATH)/sgx_sign +else + SGX_ENCLAVE_SIGNER := $(SGX_BIN_PATH)/sgx_sign_hyper + SGX_EDGER8R_MODE := --sgx-mode $(SGX_MODE) +endif + +######## CUSTOM Settings ######## + +CUSTOM_LIBRARY_PATH := ./lib +CUSTOM_BIN_PATH := ./bin +CUSTOM_SYSROOT_PATH := ./sysroot +CUSTOM_EDL_PATH := $(ROOT_DIR)/sgx_edl/edl +CUSTOM_COMMON_PATH := $(ROOT_DIR)/common + +######## EDL Settings ######## + +Enclave_EDL_Files := enclave/enclave_t.c enclave/enclave_t.h app/enclave_u.c app/enclave_u.h + +######## APP Settings ######## + +App_Rust_Flags := --release +App_Src_Files := $(shell find app/ -type f -name '*.rs') $(shell find app/ -type f -name 'Cargo.toml') +App_Include_Paths := -I ./app -I$(SGX_SDK)/include -I$(CUSTOM_COMMON_PATH)/inc -I$(CUSTOM_EDL_PATH) +App_C_Flags := $(CFLAGS) $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) + +App_Rust_Path := ./app/target/release +App_Enclave_u_Object := $(CUSTOM_LIBRARY_PATH)/libenclave_u.a +App_Name := $(CUSTOM_BIN_PATH)/app + +######## Enclave Settings ######## + +# BUILD_STD=no use no_std +# BUILD_STD=cargo use cargo-std-aware +# BUILD_STD=xargo use xargo +BUILD_STD ?= no + +Rust_Build_Target := x86_64-unknown-linux-sgx +Rust_Target_Path := $(ROOT_DIR)/rustlib + +ifeq ($(BUILD_STD), cargo) + Rust_Build_Std := $(Rust_Build_Flags) -Zbuild-std=core,alloc + Rust_Std_Features := + Rust_Target_Flags := --target $(Rust_Target_Path)/$(Rust_Build_Target).json + Rust_Sysroot_Path := $(CURDIR)/sysroot + Rust_Sysroot_Flags := RUSTFLAGS="--sysroot $(Rust_Sysroot_Path)" +endif + +RustEnclave_Build_Flags := $(Rust_Build_Flags) +RustEnclave_Src_Files := $(shell find enclave/ -type f -name '*.rs') $(shell find enclave/ -type f -name 'Cargo.toml') +RustEnclave_Include_Paths := -I$(CUSTOM_COMMON_PATH)/inc -I$(CUSTOM_COMMON_PATH)/inc/tlibc -I$(CUSTOM_EDL_PATH) + +RustEnclave_Link_Libs := -L$(CUSTOM_LIBRARY_PATH) -lenclave +RustEnclave_C_Flags := $(CFLAGS) $(ENCLAVE_CFLAGS) $(SGX_COMMON_CFLAGS) $(RustEnclave_Include_Paths) +RustEnclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ + -Wl,--start-group $(RustEnclave_Link_Libs) -Wl,--end-group \ + -Wl,--version-script=enclave/enclave.lds \ + $(ENCLAVE_LDFLAGS) + +ifeq ($(BUILD_STD), cargo) + RustEnclave_Out_Path := ./enclave/target/$(Rust_Build_Target)/$(Rust_Build_Out) +else ifeq ($(BUILD_STD), xargo) + RustEnclave_Out_Path := ./enclave/target/$(Rust_Build_Target)/$(Rust_Build_Out) +else + RustEnclave_Out_Path := ./enclave/target/$(Rust_Build_Out) +endif + +RustEnclave_Lib_Name := $(RustEnclave_Out_Path)/libemmtest.a +RustEnclave_Name := $(CUSTOM_BIN_PATH)/enclave.so +RustEnclave_Signed_Name := $(CUSTOM_BIN_PATH)/enclave.signed.so + +.PHONY: all +all: $(Enclave_EDL_Files) $(App_Name) $(RustEnclave_Signed_Name) + +######## EDL Objects ######## + +$(Enclave_EDL_Files): $(SGX_EDGER8R) enclave/enclave.edl + $(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --trusted enclave/enclave.edl --search-path $(CUSTOM_COMMON_PATH)/inc --search-path $(CUSTOM_EDL_PATH) --trusted-dir enclave + $(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --untrusted enclave/enclave.edl --search-path $(CUSTOM_COMMON_PATH)/inc --search-path $(CUSTOM_EDL_PATH) --untrusted-dir app + @echo "GEN => $(Enclave_EDL_Files)" + +######## App Objects ######## + +app/enclave_u.o: $(Enclave_EDL_Files) + @$(CC) $(App_C_Flags) -c app/enclave_u.c -o $@ + +$(App_Enclave_u_Object): app/enclave_u.o + @mkdir -p $(CUSTOM_LIBRARY_PATH) + @$(AR) rcsD $@ $^ + +$(App_Name): $(App_Enclave_u_Object) app + @mkdir -p $(CUSTOM_BIN_PATH) + @cp $(App_Rust_Path)/app $(CUSTOM_BIN_PATH) + @echo "LINK => $@" + +######## Enclave Objects ######## + +enclave/enclave_t.o: $(Enclave_EDL_Files) + @$(CC) $(RustEnclave_C_Flags) -c enclave/enclave_t.c -o $@ + +$(RustEnclave_Name): enclave/enclave_t.o enclave + @mkdir -p $(CUSTOM_LIBRARY_PATH) + @mkdir -p $(CUSTOM_BIN_PATH) + @cp $(RustEnclave_Lib_Name) $(CUSTOM_LIBRARY_PATH)/libenclave.a + @$(CXX) enclave/enclave_t.o -o $@ $(RustEnclave_Link_Flags) + @echo "LINK => $@" + +$(RustEnclave_Signed_Name): $(RustEnclave_Name) enclave/config.xml + @$(SGX_ENCLAVE_SIGNER) sign -key enclave/private.pem -enclave $(RustEnclave_Name) -out $@ -config enclave/config.xml + @echo "SIGN => $@" + +######## Build App ######## + +.PHONY: app +app: + @cd app && SGX_SDK=$(SGX_SDK) cargo build $(App_Rust_Flags) + +######## Build Enclave ######## + +.PHONY: enclave +enclave: +ifeq ($(BUILD_STD), cargo) + @cd $(Rust_Target_Path)/std && cargo build $(Rust_Build_Std) $(Rust_Target_Flags) $(Rust_Std_Features) + + @rm -rf $(Rust_Sysroot_Path) + @mkdir -p $(Rust_Sysroot_Path)/lib/rustlib/$(Rust_Build_Target)/lib + @cp -r $(Rust_Target_Path)/std/target/$(Rust_Build_Target)/$(Rust_Build_Out)/deps/* $(Rust_Sysroot_Path)/lib/rustlib/$(Rust_Build_Target)/lib + + @cd enclave && $(Rust_Sysroot_Flags) cargo build $(Rust_Target_Flags) $(RustEnclave_Build_Flags) + +else ifeq ($(BUILD_STD), xargo) + @cd enclave && RUST_TARGET_PATH=$(Rust_Target_Path) xargo build --target $(Rust_Build_Target) $(RustEnclave_Build_Flags) +else + @cd enclave && cargo build $(RustEnclave_Build_Flags) +endif + +######## Run Enclave ######## + +.PHONY: run +run: $(App_Name) $(RustEnclave_Signed_Name) + @echo -e '\n===== Run Enclave =====\n' + @cd bin && ./app + +.PHONY: clean +clean: + @rm -f $(App_Name) $(RustEnclave_Name) $(RustEnclave_Signed_Name) enclave/*_t.* app/*_u.* + @cd enclave && cargo clean + @cd app && cargo clean + @cd $(Rust_Target_Path)/std && cargo clean + @rm -rf $(CUSTOM_BIN_PATH) $(CUSTOM_LIBRARY_PATH) $(CUSTOM_SYSROOT_PATH) diff --git a/samplecode/emm/app/Cargo.toml b/samplecode/emm/app/Cargo.toml new file mode 100644 index 000000000..a6370f740 --- /dev/null +++ b/samplecode/emm/app/Cargo.toml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +[package] +name = "app" +version = "1.0.0" +authors = ["The Teaclave Authors"] +edition = "2021" + +[dependencies] +sgx_types = { path = "../../../sgx_types" } +sgx_urts = { path = "../../../sgx_urts" } + +[profile.dev] +opt-level = 0 +debug = true \ No newline at end of file diff --git a/samplecode/emm/app/build.rs b/samplecode/emm/app/build.rs new file mode 100644 index 000000000..23b8f5e70 --- /dev/null +++ b/samplecode/emm/app/build.rs @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +use std::env; + +fn main() { + println!("cargo:rerun-if-env-changed=SGX_MODE"); + println!("cargo:rerun-if-changed=build.rs"); + + let sdk_dir = env::var("SGX_SDK").unwrap_or_else(|_| "/opt/intel/sgxsdk".to_string()); + let mode = env::var("SGX_MODE").unwrap_or_else(|_| "HW".to_string()); + + println!("cargo:rustc-link-search=native=../lib"); + println!("cargo:rustc-link-lib=static=enclave_u"); + + println!("cargo:rustc-link-search=native={}/lib64", sdk_dir); + match mode.as_ref() { + "SIM" | "SW" => println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"), + "HYPER" => println!("cargo:rustc-link-lib=dylib=sgx_urts_hyper"), + "HW" => println!("cargo:rustc-link-lib=dylib=sgx_urts"), + _ => println!("cargo:rustc-link-lib=dylib=sgx_urts"), + } +} diff --git a/samplecode/emm/app/src/main.rs b/samplecode/emm/app/src/main.rs new file mode 100644 index 000000000..6946fcd41 --- /dev/null +++ b/samplecode/emm/app/src/main.rs @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +extern crate sgx_types; +extern crate sgx_urts; + +use sgx_types::error::SgxStatus; +use sgx_types::types::*; +use sgx_urts::enclave::SgxEnclave; + +static ENCLAVE_FILE: &str = "enclave.signed.so"; + +extern "C" { + fn ecall_test_sgx_mm_unsafe(eid: EnclaveId, retval: *mut SgxStatus) -> SgxStatus; +} + +fn main() { + let enclave = match SgxEnclave::create(ENCLAVE_FILE, true) { + Ok(enclave) => { + println!("[+] Init Enclave Successful {}!", enclave.eid()); + enclave + } + Err(err) => { + println!("[-] Init Enclave Failed {}!", err.as_str()); + return; + } + }; + + // let input_string = String::from("This is a normal world string passed into Enclave!\n"); + let mut retval = SgxStatus::Success; + + let result = unsafe { ecall_test_sgx_mm_unsafe(enclave.eid(), &mut retval) }; + match result { + SgxStatus::Success => println!("[+] ECall Success..."), + _ => println!("[-] ECall Enclave Failed {}!", result.as_str()), + } +} diff --git a/samplecode/emm/enclave/Cargo.toml b/samplecode/emm/enclave/Cargo.toml new file mode 100644 index 000000000..e6e7d1f15 --- /dev/null +++ b/samplecode/emm/enclave/Cargo.toml @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +[package] +name = "emmtest" +version = "1.0.0" +authors = ["The Teaclave Authors"] +edition = "2021" + +[lib] +name = "emmtest" +crate-type = ["staticlib"] + +[features] +default = [] + +[target.'cfg(not(target_vendor = "teaclave"))'.dependencies] +sgx_types = { path = "../../../sgx_types"} +sgx_tstd = { path = "../../../sgx_tstd", features = ["thread"]} +sgx_trts = { path = "../../../sgx_trts" } diff --git a/samplecode/emm/enclave/Xargo.toml b/samplecode/emm/enclave/Xargo.toml new file mode 100644 index 000000000..d1d0e6d1b --- /dev/null +++ b/samplecode/emm/enclave/Xargo.toml @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +[dependencies] +alloc = {} + +[dependencies.std] +path = "../../../rustlib/std" +stage = 1 diff --git a/samplecode/emm/enclave/config.xml b/samplecode/emm/enclave/config.xml new file mode 100644 index 000000000..36f822e6c --- /dev/null +++ b/samplecode/emm/enclave/config.xml @@ -0,0 +1,38 @@ + + + + 0 + 0 + 250 + 3 + 0 + 250 + + 0x10000 + 0x4000 + 0xF0000000 + 0x9000 + 0x08000 + 0x90000000 + 0 + 1 + 0xFFFFFFFF + diff --git a/samplecode/emm/enclave/enclave.edl b/samplecode/emm/enclave/enclave.edl new file mode 100644 index 000000000..8e60d0ad7 --- /dev/null +++ b/samplecode/emm/enclave/enclave.edl @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +enclave { + from "sgx_stdio.edl" import *; + from "sgx_tstd.edl" import *; + from "sgx_thread.edl" import *; + + // from "sgx_tstdc.edl" import sgx_thread_wait_untrusted_event_ocall, sgx_thread_set_untrusted_event_ocall; + trusted { + // public sgx_status_t ecall_test_sgx_mm(int seq_id); + public sgx_status_t ecall_test_sgx_mm_unsafe(void); + // public size_t ecall_alloc_context(void); + // public sgx_status_t ecall_check_context(size_t tcs); + // public sgx_status_t ecall_dealloc_context(size_t tcs); + }; + // untrusted { + // void ocall_print_string([in, string] const char *str); + // }; + +}; \ No newline at end of file diff --git a/samplecode/emm/enclave/enclave.lds b/samplecode/emm/enclave/enclave.lds new file mode 100644 index 000000000..bdb7a4b53 --- /dev/null +++ b/samplecode/emm/enclave/enclave.lds @@ -0,0 +1,12 @@ +enclave.so +{ + global: + g_global_data_hyper; + g_global_data_sim; + g_global_data; + enclave_entry; + g_peak_heap_used; + g_peak_rsrv_mem_committed; + local: + *; +}; diff --git a/samplecode/emm/enclave/private.pem b/samplecode/emm/enclave/private.pem new file mode 100644 index 000000000..529d07be3 --- /dev/null +++ b/samplecode/emm/enclave/private.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4gIBAAKCAYEAroOogvsj/fZDZY8XFdkl6dJmky0lRvnWMmpeH41Bla6U1qLZ +AmZuyIF+mQC/cgojIsrBMzBxb1kKqzATF4+XwPwgKz7fmiddmHyYz2WDJfAjIveJ +ZjdMjM4+EytGlkkJ52T8V8ds0/L2qKexJ+NBLxkeQLfV8n1mIk7zX7jguwbCG1Pr +nEMdJ3Sew20vnje+RsngAzdPChoJpVsWi/K7cettX/tbnre1DL02GXc5qJoQYk7b +3zkmhz31TgFrd9VVtmUGyFXAysuSAb3EN+5VnHGr0xKkeg8utErea2FNtNIgua8H +ONfm9Eiyaav1SVKzPHlyqLtcdxH3I8Wg7yqMsaprZ1n5A1v/levxnL8+It02KseD +5HqV4rf/cImSlCt3lpRg8U5E1pyFQ2IVEC/XTDMiI3c+AR+w2jSRB3Bwn9zJtFlW +KHG3m1xGI4ck+Lci1JvWWLXQagQSPtZTsubxTQNx1gsgZhgv1JHVZMdbVlAbbRMC +1nSuJNl7KPAS/VfzAgEDAoIBgHRXxaynbVP5gkO0ug6Qw/E27wzIw4SmjsxG6Wpe +K7kfDeRskKxESdsA/xCrKkwGwhcx1iIgS5+Qscd1Yg+1D9X9asd/P7waPmWoZd+Z +AhlKwhdPsO7PiF3e1AzHhGQwsUTt/Y/aSI1MpHBvy2/s1h9mFCslOUxTmWw0oj/Q +ldIEgWeNR72CE2+jFIJIyml6ftnb6qzPiga8Bm48ubKh0kvySOqnkmnPzgh+JBD6 +JnBmtZbfPT97bwTT+N6rnPqOOApvfHPf15kWI8yDbprG1l4OCUaIUH1AszxLd826 +5IPM+8gINLRDP1MA6azECPjTyHXhtnSIBZCyWSVkc05vYmNXYUNiXWMajcxW9M02 +wKzFELO8NCEAkaTPxwo4SCyIjUxiK1LbQ9h8PSy4c1+gGP4LAMR8xqP4QKg6zdu9 +osUGG/xRe/uufgTBFkcjqBHtK5L5VI0jeNIUAgW/6iNbYXjBMJ0GfauLs+g1VsOm +WfdgXzsb9DYdMa0OXXHypmV4GwKBwQDUwQj8RKJ6c8cT4vcWCoJvJF00+RFL+P3i +Gx2DLERxRrDa8AVGfqaCjsR+3vLgG8V/py+z+dxZYSqeB80Qeo6PDITcRKoeAYh9 +xlT3LJOS+k1cJcEmlbbO2IjLkTmzSwa80fWexKu8/Xv6vv15gpqYl1ngYoqJM3pd +vzmTIOi7MKSZ0WmEQavrZj8zK4endE3v0eAEeQ55j1GImbypSf7Idh7wOXtjZ7WD +Dg6yWDrri+AP/L3gClMj8wsAxMV4ZR8CgcEA0fzDHkFa6raVOxWnObmRoDhAtE0a +cjUj976NM5yyfdf2MrKy4/RhdTiPZ6b08/lBC/+xRfV3xKVGzacm6QjqjZrUpgHC +0LKiZaMtccCJjLtPwQd0jGQEnKfMFaPsnhOc5y8qVkCzVOSthY5qhz0XNotHHFmJ +gffVgB0iqrMTvSL7IA2yqqpOqNRlhaYhNl8TiFP3gIeMtVa9rZy31JPgT2uJ+kfo +gV7sdTPEjPWZd7OshGxWpT6QfVDj/T9T7L6tAoHBAI3WBf2DFvxNL2KXT2QHAZ9t +k3imC4f7U+wSE6zILaDZyzygA4RUbwG0gv8/TJVn2P/Eynf76DuWHGlaiLWnCbSz +Az2DHBQBBaku409zDQym3j1ugMRjzzSQWzJg0SIyBH3hTmnYcn3+Uqcp/lEBvGW6 +O+rsXFt3pukqJmIV8HzLGGaLm62BHUeZf3dyWm+i3p/hQAL7Xvu04QW70xuGqdr5 +afV7p5eaeQIJXyGQJ0eylV/90+qxjMKiB1XYg6WYvwKBwQCL/ddpgOdHJGN8uRom +e7Zq0Csi3hGheMKlKbN3vcxT5U7MdyHtTZZOJbTvxKNNUNYH/8uD+PqDGNneb29G +BfGzvI3EASyLIcGZF3OhKwZd0jUrWk2y7Vhob91jwp2+t73vdMbkKyI4mHOuXvGv +fg95si9oO7EBT+Oqvhccd2J+F1IVXncccYnF4u5ZGWt5lLewN/pVr7MjjykeaHqN +t+rfnQam2psA6fL4zS2zTmZPzR2tnY8Y1GBTi0Ko1OKd1HMCgcAb5cB/7/AQlhP9 +yQa04PLH9ygQkKKptZp7dy5WcWRx0K/hAHRoi2aw1wZqfm7VBNu2SLcs90kCCCxp +6C5sfJi6b8NpNbIPC+sc9wsFr7pGo9SFzQ78UlcWYK2Gu2FxlMjonhka5hvo4zvg +WxlpXKEkaFt3gLd92m/dMqBrHfafH7VwOJY2zT3WIpjwuk0ZzmRg5p0pG/svVQEH +NZmwRwlopysbR69B/n1nefJ84UO50fLh5s5Zr3gBRwbWNZyzhXk= +-----END RSA PRIVATE KEY----- diff --git a/samplecode/emm/enclave/src/lib.rs b/samplecode/emm/enclave/src/lib.rs new file mode 100644 index 000000000..daaaf1777 --- /dev/null +++ b/samplecode/emm/enclave/src/lib.rs @@ -0,0 +1,396 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License.. + +#![cfg_attr(not(target_vendor = "teaclave"), no_std)] +#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))] +#![feature(pointer_byte_offsets)] + +#[cfg(not(target_vendor = "teaclave"))] +#[macro_use] +extern crate sgx_tstd as std; +extern crate sgx_trts; +extern crate sgx_types; + +use core::ffi::c_void; +use sgx_trts::emm::{self, AllocFlags, PageInfo, PageType, PfHandler, PfInfo, ProtFlags}; +use sgx_trts::veh::HandleResult; +use sgx_types::error::errno::{EACCES, EEXIST, EINVAL, EPERM}; +use sgx_types::error::SgxStatus; +use std::io::{self, Write}; +use std::slice; +use std::string::String; +use std::string::ToString; +use std::thread; +use std::vec::Vec; + +const ALLOC_SIZE: usize = 0x2000; +const SE_PAGE_SIZE: usize = 0x1000; + +#[no_mangle] +fn ecall_test_sgx_mm_unsafe() -> SgxStatus { + let input_string = "Enclave memory management test: \n"; + unsafe { + say_something(input_string.as_ptr(), input_string.len()); + } + test_emm_alloc_dealloc(); + test_stack_expand(); + test_commit_and_uncommit(); + test_modify_types(); + test_dynamic_expand_tcs(); + test_modify_perms() +} + +#[derive(Clone, Copy, Default)] +struct PfData { + pf: PfInfo, + access: i32, + addr_expected: usize, +} + +pub extern "C" fn permission_pfhandler(info: &mut PfInfo, priv_data: *mut c_void) -> HandleResult { + let mut pd = unsafe { &mut *(priv_data as *mut PfData) }; + pd.pf = *info; + + let addr = pd.pf.maddr as usize; + let prot = ProtFlags::from_bits(pd.access as u8).unwrap(); + let rw_bit = unsafe { pd.pf.pfec.bits.rw() }; + if (rw_bit == 1) && (prot == ProtFlags::W) { + emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, ProtFlags::W | ProtFlags::R); + } else if (rw_bit == 0) && prot.contains(ProtFlags::R) { + emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, prot); + } else { + panic!() + } + + HandleResult::Execution +} + +#[no_mangle] +fn test_modify_perms() -> SgxStatus { + let mut pd = PfData::default(); + + // example 1: + let base = emm::user_mm_alloc( + None, + ALLOC_SIZE, + AllocFlags::COMMIT_NOW, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + Some(permission_pfhandler), + Some(&mut pd as *mut PfData as *mut c_void), + ) + .unwrap(); + + let data = unsafe { (base as *const u8).read() }; + assert!(data == 0); + + // read success without PF + assert!(unsafe { pd.pf.pfec.errcd } == 0); + unsafe { (base as *mut u8).write(0xFF) }; + + // write success without PF + assert!(unsafe { pd.pf.pfec.errcd } == 0); + + let res = emm::user_mm_modify_perms(base, ALLOC_SIZE / 2, ProtFlags::R); + assert!(res.is_ok()); + + pd.access = ProtFlags::R.bits() as i32; + let data = unsafe { (base as *const u8).read() }; + assert!(data == 0xFF); + // read success without PF + assert!(unsafe { pd.pf.pfec.errcd } == 0); + + // 出问题了 + pd.access = ProtFlags::W.bits() as i32; + let count = (ALLOC_SIZE - 1) as isize; + unsafe { + let ptr = (base as *mut u8).byte_offset(count); + ptr.write(0xFF); + }; + // write success without PF + assert!(unsafe { pd.pf.pfec.errcd } == 0); + + pd.access = ProtFlags::W.bits() as i32; + unsafe { (base as *mut u8).write(0xFF) }; + // write success with PF + assert!(unsafe { pd.pf.pfec.errcd } != 0); + + // write indicated with PFEC + assert!(unsafe { pd.pf.pfec.bits.rw() } == 1); + + println!( + "{}", + "Successfully run modify permissions and customized page fault handler!" + ); + SgxStatus::Success +} + +#[no_mangle] +fn test_dynamic_expand_tcs() -> SgxStatus { + thread::Builder::new() + .name("thread1".to_string()) + .spawn(move || { + println!("Hello, this is a spawned thread!"); + }); + + for _ in 0..40 { + let _t = thread::spawn(move || { + println!("Hello, this is a spawned thread!"); + }); + } + + println!("{}", "Successfully dynamic expand tcs!"); + SgxStatus::Success +} + +#[no_mangle] +fn test_modify_types() -> SgxStatus { + // example 1: + let base = emm::user_mm_alloc( + None, + SE_PAGE_SIZE, + AllocFlags::COMMIT_NOW, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ) + .unwrap(); + + let res = emm::user_mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); + assert!(res.is_ok()); + + let res = emm::user_mm_uncommit(base, SE_PAGE_SIZE); + assert!(res.is_ok()); + + // example 2: + let base = emm::user_mm_alloc( + None, + SE_PAGE_SIZE, + AllocFlags::COMMIT_NOW, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ) + .unwrap(); + + let res = emm::user_mm_modify_perms(base, SE_PAGE_SIZE, ProtFlags::NONE); + assert!(res.is_ok()); + + let res = emm::user_mm_uncommit(base, SE_PAGE_SIZE); + assert!(res.is_ok()); + + // example 3: + let res = emm::user_mm_dealloc(0, ALLOC_SIZE); + assert!(res == Err(EINVAL)); + + let base = emm::user_mm_alloc( + None, + ALLOC_SIZE, + AllocFlags::COMMIT_NOW, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ) + .unwrap(); + + let res = emm::user_mm_modify_type(base + SE_PAGE_SIZE, SE_PAGE_SIZE, PageType::Frist); + assert!(res == Err(EPERM)); + + let res = emm::user_mm_modify_perms( + base + SE_PAGE_SIZE, + SE_PAGE_SIZE, + ProtFlags::R | ProtFlags::X, + ); + assert!(res.is_ok()); + + let res = emm::user_mm_modify_type(base + SE_PAGE_SIZE, SE_PAGE_SIZE, PageType::Tcs); + assert!(res == Err(EACCES)); + + let res = emm::user_mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); + assert!(res.is_ok()); + + let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + assert!(res.is_ok()); + + let res = emm::user_mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); + assert!(res == Err(EACCES)); + + let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + assert!(res.is_ok()); + + println!("{}", "Successfully run modify types!"); + SgxStatus::Success +} + +#[no_mangle] +fn test_commit_and_uncommit() -> SgxStatus { + let res = emm::user_mm_dealloc(0, ALLOC_SIZE); + assert!(res == Err(EINVAL)); + + let base = emm::user_mm_alloc( + None, + ALLOC_SIZE, + AllocFlags::COMMIT_NOW, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ) + .unwrap(); + + let res = emm::user_mm_commit(base, ALLOC_SIZE); + assert!(res.is_ok()); + + let res = emm::user_mm_alloc( + Some(base), + ALLOC_SIZE, + AllocFlags::COMMIT_NOW | AllocFlags::FIXED, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ); + assert!(res == Err(EEXIST)); + + let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + assert!(res.is_ok()); + + let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + assert!(res.is_ok()); + + let res = emm::user_mm_commit(base, ALLOC_SIZE); + assert!(res.is_ok()); + + let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + assert!(res.is_ok()); + + let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + assert!(res == Err(EINVAL)); + + let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + assert!(res == Err(EINVAL)); + + let base2 = emm::user_mm_alloc( + None, + ALLOC_SIZE, + AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ) + .unwrap(); + + assert!(base == base2); + + let ptr = base2 as *mut u8; + unsafe { + ptr.write(0xFF); + ptr.offset((ALLOC_SIZE - 1) as isize).write(0xFF); + }; + + let res = emm::user_mm_dealloc(base2, ALLOC_SIZE); + assert!(res.is_ok()); + + println!("{}", "Successfully run commit and uncommit!"); + SgxStatus::Success +} + +#[no_mangle] +fn test_stack_expand() -> SgxStatus { + const STATIC_REGION: usize = 0x8000; + let mut buf = [0_u8; STATIC_REGION]; + for (idx, item) in buf.iter_mut().enumerate() { + *item = (idx % 256) as u8; + } + for (idx, item) in buf.iter().enumerate() { + assert!(*item == (idx % 256) as u8); + } + println!("{}", "Successfully expand stack!"); + SgxStatus::Success +} + +#[no_mangle] +fn test_emm_alloc_dealloc() -> SgxStatus { + let res = emm::user_mm_dealloc(0, ALLOC_SIZE); + assert!(res == Err(EINVAL)); + + let base = emm::user_mm_alloc( + None, + ALLOC_SIZE, + AllocFlags::COMMIT_NOW, + PageInfo { + typ: PageType::Reg, + prot: ProtFlags::R | ProtFlags::W, + }, + None, + None, + ) + .unwrap(); + + let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + assert!(res.is_ok()); + println!("{}", "Successfully run alloc and dealloc!"); + SgxStatus::Success +} + +/// # Safety +#[no_mangle] +unsafe fn say_something(some_string: *const u8, some_len: usize) -> SgxStatus { + let str_slice = slice::from_raw_parts(some_string, some_len); + let _ = io::stdout().write(str_slice); + + // A sample &'static string + let rust_raw_string = "This is a in-Enclave "; + // An array + let word: [u8; 4] = [82, 117, 115, 116]; + // An vector + let word_vec: Vec = vec![32, 115, 116, 114, 105, 110, 103, 33]; + + // Construct a string from &'static string + let mut hello_string = String::from(rust_raw_string); + + // Iterate on word array + for c in word.iter() { + hello_string.push(*c as char); + } + + // Rust style convertion + hello_string += String::from_utf8(word_vec).expect("Invalid UTF-8").as_str(); + + // Ocall to normal world for output + println!("{}", &hello_string); + + SgxStatus::Success +} From 9488419faf14f5da566055904344112d9d288e94 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Sun, 24 Sep 2023 22:30:36 +0800 Subject: [PATCH 12/20] Support customized pf handler with private data --- sgx_trts/src/capi.rs | 4 ++-- sgx_trts/src/emm/ema.rs | 10 +++++----- sgx_trts/src/emm/pfhandler.rs | 17 +++++++++++++---- sgx_trts/src/emm/range.rs | 12 ++++++------ 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs index d9ec21bc0..1bbca0a16 100644 --- a/sgx_trts/src/capi.rs +++ b/sgx_trts/src/capi.rs @@ -19,7 +19,7 @@ use crate::arch::SE_PAGE_SIZE; use crate::call::{ocall, OCallIndex, OcBuffer}; use crate::emm::alloc::Alloc; use crate::emm::page::AllocFlags; -use crate::emm::pfhandler::{PfHandler, PfInfo}; +use crate::emm::pfhandler::PfHandler; use crate::emm::range::{ RangeType, ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, PAGE_TYPE_MASK, PAGE_TYPE_SHIFT, RM, @@ -206,7 +206,7 @@ pub unsafe extern "C" fn sgx_mm_alloc( size: usize, flags: usize, handler: *mut c_void, - priv_data: *mut PfInfo, + priv_data: *mut c_void, out_addr: *mut *mut u8, ) -> u32 { let handler = if handler.is_null() { diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index fa0a75d9f..675ab9f9d 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -20,7 +20,7 @@ use crate::emm::{PageInfo, PageRange, PageType, ProtFlags}; use crate::enclave::is_within_enclave; use alloc::boxed::Box; use intrusive_collections::{intrusive_adapter, LinkedListLink, UnsafeRef}; -use sgx_tlibc_sys::{EACCES, EFAULT, EINVAL}; +use sgx_tlibc_sys::{c_void, EACCES, EINVAL}; use sgx_types::error::OsResult; use super::alloc::Alloc; @@ -28,7 +28,7 @@ use super::alloc::{ResAlloc, StaticAlloc}; use super::bitmap::BitArray; use super::ocall; use super::page::AllocFlags; -use super::pfhandler::{PfHandler, PfInfo}; +use super::pfhandler::PfHandler; /// Enclave Management Area #[repr(C)] @@ -45,7 +45,7 @@ pub struct EMA { // custom PF handler handler: Option, // private data for PF handler - priv_data: Option<*mut PfInfo>, + priv_data: Option<*mut c_void>, alloc: Alloc, // intrusive linkedlist link: LinkedListLink, @@ -64,7 +64,7 @@ impl EMA { alloc_flags: AllocFlags, info: PageInfo, handler: Option, - priv_data: Option<*mut PfInfo>, + priv_data: Option<*mut c_void>, alloc: Alloc, ) -> OsResult { // check alloc flags' eligibility @@ -605,7 +605,7 @@ impl EMA { self.info } - pub fn fault_handler(&self) -> (Option, Option<*mut PfInfo>) { + pub fn fault_handler(&self) -> (Option, Option<*mut c_void>) { (self.handler, self.priv_data) } } diff --git a/sgx_trts/src/emm/pfhandler.rs b/sgx_trts/src/emm/pfhandler.rs index cbebc2dc3..8ca0b2063 100644 --- a/sgx_trts/src/emm/pfhandler.rs +++ b/sgx_trts/src/emm/pfhandler.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License.. +use sgx_tlibc_sys::c_void; + use crate::{ emm::ProtFlags, emm::{ @@ -25,6 +27,7 @@ use crate::{ }; #[repr(C)] +#[derive(Clone, Copy, Default)] pub struct PfInfo { pub maddr: u64, // address for #PF. pub pfec: Pfec, @@ -32,13 +35,20 @@ pub struct PfInfo { } #[repr(C)] +#[derive(Clone, Copy)] pub union Pfec { pub errcd: u32, pub bits: PfecBits, } +impl Default for Pfec { + fn default() -> Self { + Pfec { errcd: 0 } + } +} + #[repr(C, packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Default)] pub struct PfecBits(u32); impl PfecBits { @@ -83,7 +93,7 @@ impl PfecBits { } } -pub type PfHandler = extern "C" fn(info: &mut PfInfo) -> HandleResult; +pub type PfHandler = extern "C" fn(info: &mut PfInfo, priv_data: *mut c_void) -> HandleResult; pub extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { let addr = trim_to_page!(info.maddr as usize); @@ -103,8 +113,7 @@ pub extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { let (handler, priv_data) = ema.fault_handler(); if let Some(handler) = handler { drop(range_manage); - let mut pf_info = unsafe { priv_data.unwrap().read() }; - return handler(&mut pf_info); + return handler(info, priv_data.unwrap()); } // No customized page fault handler diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index b83115bc7..baa2e6ce0 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -23,7 +23,7 @@ use crate::{ }; use alloc::boxed::Box; use intrusive_collections::{linked_list::CursorMut, LinkedList, UnsafeRef}; -use sgx_tlibc_sys::{EEXIST, EINVAL, ENOMEM, EPERM}; +use sgx_tlibc_sys::{c_void, EEXIST, EINVAL, ENOMEM, EPERM}; use sgx_types::error::OsResult; use spin::Once; @@ -31,7 +31,7 @@ use super::{ alloc::{Alloc, ResAlloc, StaticAlloc}, ema::{EmaAda, EMA}, page::AllocFlags, - pfhandler::{PfHandler, PfInfo}, + pfhandler::PfHandler, }; pub const ALLOC_FLAGS_SHIFT: usize = 0; @@ -58,7 +58,7 @@ pub fn user_mm_alloc( alloc_flags: AllocFlags, info: PageInfo, handler: Option, - priv_data: Option<*mut PfInfo>, + priv_data: Option<*mut c_void>, ) -> OsResult { let mut range_manage = RM.get().unwrap().lock(); range_manage.alloc( @@ -104,7 +104,7 @@ pub fn rts_mm_alloc( alloc_flags: AllocFlags, info: PageInfo, handler: Option, - priv_data: Option<*mut PfInfo>, + priv_data: Option<*mut c_void>, ) -> OsResult { let mut range_manage = RM.get().unwrap().lock(); range_manage.alloc( @@ -175,7 +175,7 @@ impl RangeManage { alloc_flags: AllocFlags, info: PageInfo, handler: Option, - priv_data: Option<*mut PfInfo>, + priv_data: Option<*mut c_void>, ) -> OsResult { ensure!( addr != 0 && size != 0 && is_within_enclave(addr as *const u8, size), @@ -255,7 +255,7 @@ impl RangeManage { alloc_flags: AllocFlags, info: PageInfo, handler: Option, - priv_data: Option<*mut PfInfo>, + priv_data: Option<*mut c_void>, typ: RangeType, alloc: Alloc, ) -> OsResult { From 6475345e5390285e1bfdbb241b1d10e230c12c65 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Tue, 26 Sep 2023 17:01:28 +0800 Subject: [PATCH 13/20] Modify libc and rsrvmm with emm --- common/inc/internal/trts_inst.h | 4 +- sgx_libc/sgx_tlibc_sys/tlibc/gen/sbrk.c | 4 +- sgx_rsrvmm/src/rsrvmm/area.rs | 48 ++++++++----------- sgx_rsrvmm/src/rsrvmm/mod.rs | 2 +- sgx_trts/src/capi.rs | 12 ++--- sgx_trts/src/emm/mod.rs | 7 +-- sgx_trts/src/emm/ocall.rs | 52 +-------------------- sgx_trts/src/emm/page.rs | 57 ++--------------------- sgx_trts/src/emm/trim.rs | 62 ------------------------- 9 files changed, 38 insertions(+), 210 deletions(-) delete mode 100644 sgx_trts/src/emm/trim.rs diff --git a/common/inc/internal/trts_inst.h b/common/inc/internal/trts_inst.h index 4a86ce222..9121efb29 100644 --- a/common/inc/internal/trts_inst.h +++ b/common/inc/internal/trts_inst.h @@ -89,8 +89,8 @@ uint32_t sgx_get_rsrvmm_default_perm(void); size_t get_stack_guard(void); -int sgx_apply_epc_pages(void *start_address, size_t page_number); -int sgx_trim_epc_pages(void *start_address, size_t page_number); +int sgx_commit_rts_pages(void *start_address, size_t page_number); +int sgx_uncommit_rts_pages(void *start_address, size_t page_number); #ifdef __cplusplus } diff --git a/sgx_libc/sgx_tlibc_sys/tlibc/gen/sbrk.c b/sgx_libc/sgx_tlibc_sys/tlibc/gen/sbrk.c index 203714f09..91ee5312d 100644 --- a/sgx_libc/sgx_tlibc_sys/tlibc/gen/sbrk.c +++ b/sgx_libc/sgx_tlibc_sys/tlibc/gen/sbrk.c @@ -122,7 +122,7 @@ void* sbrk(intptr_t n) size = prev_heap_used - heap_min_size; } assert((size & (SE_PAGE_SIZE - 1)) == 0); - int ret = sgx_trim_epc_pages(start_addr, size >> SE_PAGE_SHIFT); + int ret = sgx_uncommit_rts_pages(start_addr, size >> SE_PAGE_SHIFT); if (ret != 0) { heap_used = prev_heap_used; @@ -166,7 +166,7 @@ void* sbrk(intptr_t n) size = heap_used - heap_min_size; } assert((size & (SE_PAGE_SIZE - 1)) == 0); - int ret = sgx_apply_epc_pages(start_addr, size >> SE_PAGE_SHIFT); + int ret = sgx_commit_rts_pages(start_addr, size >> SE_PAGE_SHIFT); if (ret != 0) { heap_used = prev_heap_used; diff --git a/sgx_rsrvmm/src/rsrvmm/area.rs b/sgx_rsrvmm/src/rsrvmm/area.rs index 105dea920..6e2f1588c 100644 --- a/sgx_rsrvmm/src/rsrvmm/area.rs +++ b/sgx_rsrvmm/src/rsrvmm/area.rs @@ -22,10 +22,9 @@ use alloc_crate::vec::Vec; use core::any::TypeId; use core::cmp::{self, Ordering}; use core::convert::From; -use core::fmt; use core::ops::{Deref, DerefMut}; -use sgx_trts::emm::{modpr_ocall, mprotect_ocall}; -use sgx_trts::emm::{ProtFlags, PageInfo, PageRange, PageType}; +use core::{fmt, panic}; +use sgx_trts::emm::{rts_mm_modify_perms, ProtFlags}; use sgx_trts::trts; use sgx_types::error::errno::*; use sgx_types::error::OsResult; @@ -63,6 +62,18 @@ impl Default for MmPerm { } } +impl From for ProtFlags { + fn from(p: MmPerm) -> ProtFlags { + match p { + MmPerm::None => ProtFlags::NONE, + MmPerm::R => ProtFlags::R, + MmPerm::RW => ProtFlags::RW, + MmPerm::RX => ProtFlags::RX, + MmPerm::RWX => ProtFlags::RWX, + } + } +} + impl From for MmPerm { fn from(perm: ProtectPerm) -> MmPerm { match perm { @@ -350,38 +361,17 @@ impl MmArea { } let count = self.size() >> SE_PAGE_SHIFT; - let perm: ProtectPerm = new_perm.into(); + let prot: ProtFlags = new_perm.into(); if trts::is_supported_edmm() { let (pe_needed, pr_needed) = self.is_needed_modify_perm(new_perm)?; if pe_needed || pr_needed { - modpr_ocall(self.start(), count, perm).unwrap(); - } - - let pages = PageRange::new( - self.start(), - count, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::from_bits_truncate(perm.into()) | ProtFlags::PR, - }, - ) - .map_err(|_| EINVAL)?; - - if pe_needed { - let _ = pages.modpe(); - } - - if pr_needed && new_perm != MmPerm::RWX { - let _ = pages.accept_forward(); - } - - if pr_needed && new_perm == MmPerm::None { - mprotect_ocall(self.start(), count, perm).unwrap(); + let res = rts_mm_modify_perms(self.start(), count << SE_PAGE_SHIFT, prot); + if res.is_err() { + panic!() + } } - } else { - mprotect_ocall(self.start(), count, perm).unwrap(); } self.perm = new_perm; diff --git a/sgx_rsrvmm/src/rsrvmm/mod.rs b/sgx_rsrvmm/src/rsrvmm/mod.rs index e4299c94f..f796851d5 100644 --- a/sgx_rsrvmm/src/rsrvmm/mod.rs +++ b/sgx_rsrvmm/src/rsrvmm/mod.rs @@ -161,7 +161,7 @@ impl RsrvMem { ) }; - let ret = emm::apply_epc_pages(start_addr, size >> SE_PAGE_SHIFT); + let ret = emm::rts_mm_commit(start_addr, size >> SE_PAGE_SHIFT); if ret.is_err() { self.committed_size = pre_committed; bail!(ENOMEM); diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs index 1bbca0a16..7aef93f87 100644 --- a/sgx_trts/src/capi.rs +++ b/sgx_trts/src/capi.rs @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License.. -use crate::arch::SE_PAGE_SIZE; +use crate::arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}; use crate::call::{ocall, OCallIndex, OcBuffer}; use crate::emm::alloc::Alloc; use crate::emm::page::AllocFlags; @@ -24,7 +24,7 @@ use crate::emm::range::{ RangeType, ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, PAGE_TYPE_MASK, PAGE_TYPE_SHIFT, RM, }; -use crate::emm::{apply_epc_pages, trim_epc_pages, PageInfo, PageType, ProtFlags}; +use crate::emm::{rts_mm_commit, rts_mm_uncommit, PageInfo, PageType, ProtFlags}; use crate::enclave::{self, is_within_enclave, MmLayout}; use crate::error; use crate::rand::rand; @@ -180,8 +180,8 @@ pub unsafe extern "C" fn sgx_is_outside_enclave(p: *const u8, len: usize) -> i32 #[inline] #[no_mangle] -pub unsafe extern "C" fn sgx_apply_epc_pages(addr: usize, count: usize) -> i32 { - if apply_epc_pages(addr, count).is_ok() { +pub unsafe extern "C" fn sgx_commit_rts_pages(addr: usize, count: usize) -> i32 { + if rts_mm_commit(addr, count << SE_PAGE_SHIFT).is_ok() { 0 } else { -1 @@ -190,8 +190,8 @@ pub unsafe extern "C" fn sgx_apply_epc_pages(addr: usize, count: usize) -> i32 { #[inline] #[no_mangle] -pub unsafe extern "C" fn sgx_trim_epc_pages(addr: usize, count: usize) -> i32 { - if trim_epc_pages(addr, count).is_ok() { +pub unsafe extern "C" fn sgx_uncommit_rts_pages(addr: usize, count: usize) -> i32 { + if rts_mm_uncommit(addr, count << SE_PAGE_SHIFT).is_ok() { 0 } else { -1 diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index 0a01b2586..b070934a2 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -27,12 +27,9 @@ pub(crate) mod page; pub(crate) mod pfhandler; pub(crate) mod range; pub(crate) mod tcs; -pub(crate) mod trim; -pub use ocall::{modpr_ocall, mprotect_ocall}; -pub use page::{ - apply_epc_pages, trim_epc_pages, AllocFlags, PageInfo, PageRange, PageType, ProtFlags, -}; +pub use ocall::{alloc_ocall, modify_ocall}; +pub use page::{AllocFlags, PageInfo, PageRange, PageType, ProtFlags}; pub use pfhandler::{PfHandler, PfInfo, Pfec, PfecBits}; pub use range::{ diff --git a/sgx_trts/src/emm/ocall.rs b/sgx_trts/src/emm/ocall.rs index 234d89395..16cd3ea36 100644 --- a/sgx_trts/src/emm/ocall.rs +++ b/sgx_trts/src/emm/ocall.rs @@ -25,15 +25,13 @@ cfg_if! { #[cfg(not(any(feature = "sim", feature = "hyper")))] mod hw { - use crate::arch::SE_PAGE_SHIFT; use crate::call::{ocall, OCallIndex, OcAlloc}; use crate::emm::page::AllocFlags; use crate::emm::{PageInfo, PageType}; use alloc::boxed::Box; use core::convert::Into; use sgx_tlibc_sys::EFAULT; - use sgx_types::error::{OsResult, SgxResult, SgxStatus}; - use sgx_types::types::ProtectPerm; + use sgx_types::error::OsResult; #[repr(C)] #[derive(Clone, Copy, Debug, Default)] struct EmmAllocOcall { @@ -105,42 +103,6 @@ mod hw { Err(EFAULT) } } - - #[repr(C)] - #[derive(Clone, Copy, Debug, Default)] - struct ChangePermOcall { - addr: usize, - size: usize, - perm: u64, - } - - pub fn modpr_ocall(addr: usize, count: usize, perm: ProtectPerm) -> SgxResult { - let mut change = Box::try_new_in( - ChangePermOcall { - addr, - size: count << SE_PAGE_SHIFT, - perm: Into::::into(perm) as u64, - }, - OcAlloc, - ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::Modpr, Some(change.as_mut())) - } - - pub fn mprotect_ocall(addr: usize, count: usize, perm: ProtectPerm) -> SgxResult { - let mut change = Box::try_new_in( - ChangePermOcall { - addr, - size: count << SE_PAGE_SHIFT, - perm: Into::::into(perm) as u64, - }, - OcAlloc, - ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::Mprotect, Some(change.as_mut())) - } } #[cfg(any(feature = "sim", feature = "hyper"))] @@ -169,16 +131,4 @@ mod sw { ) -> OsResult { Ok(()) } - - #[allow(clippy::unnecessary_wraps)] - #[inline] - pub fn modpr_ocall(_addr: usize, _count: usize, _perm: ProtectPerm) -> SgxResult { - Ok(()) - } - - #[allow(clippy::unnecessary_wraps)] - #[inline] - pub fn mprotect_ocall(_addr: usize, _count: usize, _perm: ProtectPerm) -> SgxResult { - Ok(()) - } } diff --git a/sgx_trts/src/emm/page.rs b/sgx_trts/src/emm/page.rs index 3e826fe62..ea239bb1b 100644 --- a/sgx_trts/src/emm/page.rs +++ b/sgx_trts/src/emm/page.rs @@ -15,15 +15,13 @@ // specific language governing permissions and limitations // under the License.. -use crate::arch::{self, Secinfo, SE_PAGE_SHIFT, SE_PAGE_SIZE}; -use crate::emm::layout::LayoutTable; -use crate::emm::trim; +use crate::arch::{Secinfo, SE_PAGE_SHIFT, SE_PAGE_SIZE}; use crate::enclave::is_within_enclave; use crate::inst::EncluInst; use bitflags::bitflags; use core::num::NonZeroUsize; use sgx_tlibc_sys::{EFAULT, EINVAL}; -use sgx_types::error::{OsResult, SgxResult, SgxStatus}; +use sgx_types::error::OsResult; use sgx_types::marker::ContiguousMemory; bitflags! { @@ -65,6 +63,9 @@ impl_bitflags! { const PENDING = 0x08; const MODIFIED = 0x10; const PR = 0x20; + const RW = Self::R.bits() | Self::W.bits(); + const RX = Self::R.bits() | Self::X.bits(); + const RWX = Self::R.bits() | Self::W.bits() | Self::X.bits(); } } @@ -239,51 +240,3 @@ impl Page { EncluInst::emodpe(&secinfo, self.addr).map_err(|_| EFAULT) } } - -pub fn apply_epc_pages(addr: usize, count: usize) -> SgxResult { - ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); - - if let Some(attr) = LayoutTable::new().check_dyn_range(addr, count, None) { - let pages = PageRange::new( - addr, - count, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, - }, - ) - .map_err(|_| SgxStatus::Unexpected)?; - if (attr.attr & arch::PAGE_DIR_GROW_DOWN) == 0 { - pages.accept_forward().map_err(|_| SgxStatus::Unexpected) - } else { - pages.accept_backward().map_err(|_| SgxStatus::Unexpected) - } - } else { - Err(SgxStatus::InvalidParameter) - } -} - -pub fn trim_epc_pages(addr: usize, count: usize) -> SgxResult { - ensure!(addr != 0 && count != 0, SgxStatus::InvalidParameter); - - LayoutTable::new() - .check_dyn_range(addr, count, None) - .ok_or(SgxStatus::InvalidParameter)?; - - trim::trim_range(addr, count)?; - - let pages = PageRange::new( - addr, - count, - PageInfo { - typ: PageType::Trim, - prot: ProtFlags::MODIFIED, - }, - ) - .map_err(|_| SgxStatus::Unexpected)?; - pages.accept_forward().map_err(|_| SgxStatus::Unexpected)?; - - trim::trim_range_commit(addr, count)?; - - Ok(()) -} diff --git a/sgx_trts/src/emm/trim.rs b/sgx_trts/src/emm/trim.rs deleted file mode 100644 index ce278cecc..000000000 --- a/sgx_trts/src/emm/trim.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License.. - -use crate::arch::SE_PAGE_SHIFT; -use crate::call::{ocall, OCallIndex, OcAlloc}; -use alloc::boxed::Box; -use sgx_types::error::{SgxResult, SgxStatus}; - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -struct TrimRangeOcall { - from: usize, - to: usize, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -struct TrimRangeCommitOcall { - addr: usize, -} - -pub fn trim_range(addr: usize, count: usize) -> SgxResult { - let mut trim = Box::try_new_in( - TrimRangeOcall { - from: addr, - to: addr + (count << SE_PAGE_SHIFT), - }, - OcAlloc, - ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::Trim, Some(trim.as_mut())) -} - -pub fn trim_range_commit(addr: usize, count: usize) -> SgxResult { - for i in 0..count { - let mut trim = Box::try_new_in( - TrimRangeCommitOcall { - addr: addr + i * SE_PAGE_SHIFT, - }, - OcAlloc, - ) - .map_err(|_| SgxStatus::OutOfMemory)?; - - ocall(OCallIndex::TrimCommit, Some(trim.as_mut()))?; - } - Ok(()) -} From 3343fadbc9ba30118af1365f0c51786a54f30f15 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Wed, 27 Sep 2023 11:35:23 +0800 Subject: [PATCH 14/20] Implement EmaOptions for reducing the number of inarguments --- samplecode/emm/enclave/src/lib.rs | 144 ++++++---------------- sgx_trts/src/capi.rs | 26 ++-- sgx_trts/src/emm/alloc.rs | 85 ++++++------- sgx_trts/src/emm/bitmap.rs | 24 ++-- sgx_trts/src/emm/ema.rs | 181 +++++++++++++++++++++------ sgx_trts/src/emm/init.rs | 128 +++++++------------ sgx_trts/src/emm/mod.rs | 2 +- sgx_trts/src/emm/page.rs | 5 +- sgx_trts/src/emm/range.rs | 197 ++++++++---------------------- sgx_trts/src/emm/tcs.rs | 16 +-- sgx_trts/src/enclave/uninit.rs | 7 +- 11 files changed, 351 insertions(+), 464 deletions(-) diff --git a/samplecode/emm/enclave/src/lib.rs b/samplecode/emm/enclave/src/lib.rs index daaaf1777..176ed5b47 100644 --- a/samplecode/emm/enclave/src/lib.rs +++ b/samplecode/emm/enclave/src/lib.rs @@ -26,7 +26,7 @@ extern crate sgx_trts; extern crate sgx_types; use core::ffi::c_void; -use sgx_trts::emm::{self, AllocFlags, PageInfo, PageType, PfHandler, PfInfo, ProtFlags}; +use sgx_trts::emm::{self, AllocFlags, EmaOptions, PageType, PfInfo, ProtFlags}; use sgx_trts::veh::HandleResult; use sgx_types::error::errno::{EACCES, EEXIST, EINVAL, EPERM}; use sgx_types::error::SgxStatus; @@ -69,9 +69,13 @@ pub extern "C" fn permission_pfhandler(info: &mut PfInfo, priv_data: *mut c_void let prot = ProtFlags::from_bits(pd.access as u8).unwrap(); let rw_bit = unsafe { pd.pf.pfec.bits.rw() }; if (rw_bit == 1) && (prot == ProtFlags::W) { - emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, ProtFlags::W | ProtFlags::R); + if emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, ProtFlags::W | ProtFlags::R).is_err() { + panic!() + }; } else if (rw_bit == 0) && prot.contains(ProtFlags::R) { - emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, prot); + if emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, prot).is_err() { + panic!() + }; } else { panic!() } @@ -82,20 +86,13 @@ pub extern "C" fn permission_pfhandler(info: &mut PfInfo, priv_data: *mut c_void #[no_mangle] fn test_modify_perms() -> SgxStatus { let mut pd = PfData::default(); - // example 1: - let base = emm::user_mm_alloc( - None, - ALLOC_SIZE, - AllocFlags::COMMIT_NOW, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, + let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + options.handle( Some(permission_pfhandler), Some(&mut pd as *mut PfData as *mut c_void), - ) - .unwrap(); + ); + let base = emm::user_mm_alloc(&mut options).unwrap(); let data = unsafe { (base as *const u8).read() }; assert!(data == 0); @@ -116,7 +113,6 @@ fn test_modify_perms() -> SgxStatus { // read success without PF assert!(unsafe { pd.pf.pfec.errcd } == 0); - // 出问题了 pd.access = ProtFlags::W.bits() as i32; let count = (ALLOC_SIZE - 1) as isize; unsafe { @@ -134,10 +130,7 @@ fn test_modify_perms() -> SgxStatus { // write indicated with PFEC assert!(unsafe { pd.pf.pfec.bits.rw() } == 1); - println!( - "{}", - "Successfully run modify permissions and customized page fault handler!" - ); + println!("Successfully run modify permissions and customized page fault handler!"); SgxStatus::Success } @@ -147,7 +140,8 @@ fn test_dynamic_expand_tcs() -> SgxStatus { .name("thread1".to_string()) .spawn(move || { println!("Hello, this is a spawned thread!"); - }); + }) + .expect("Failed to create thread!"); for _ in 0..40 { let _t = thread::spawn(move || { @@ -155,25 +149,15 @@ fn test_dynamic_expand_tcs() -> SgxStatus { }); } - println!("{}", "Successfully dynamic expand tcs!"); + println!("Successfully dynamic expand tcs!"); SgxStatus::Success } #[no_mangle] fn test_modify_types() -> SgxStatus { // example 1: - let base = emm::user_mm_alloc( - None, - SE_PAGE_SIZE, - AllocFlags::COMMIT_NOW, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ) - .unwrap(); + let mut options = EmaOptions::new(0, SE_PAGE_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::user_mm_alloc(&mut options).unwrap(); let res = emm::user_mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); assert!(res.is_ok()); @@ -182,18 +166,8 @@ fn test_modify_types() -> SgxStatus { assert!(res.is_ok()); // example 2: - let base = emm::user_mm_alloc( - None, - SE_PAGE_SIZE, - AllocFlags::COMMIT_NOW, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ) - .unwrap(); + let mut options = EmaOptions::new(0, SE_PAGE_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::user_mm_alloc(&mut options).unwrap(); let res = emm::user_mm_modify_perms(base, SE_PAGE_SIZE, ProtFlags::NONE); assert!(res.is_ok()); @@ -205,18 +179,8 @@ fn test_modify_types() -> SgxStatus { let res = emm::user_mm_dealloc(0, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let base = emm::user_mm_alloc( - None, - ALLOC_SIZE, - AllocFlags::COMMIT_NOW, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ) - .unwrap(); + let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::user_mm_alloc(&mut options).unwrap(); let res = emm::user_mm_modify_type(base + SE_PAGE_SIZE, SE_PAGE_SIZE, PageType::Frist); assert!(res == Err(EPERM)); @@ -243,7 +207,7 @@ fn test_modify_types() -> SgxStatus { let res = emm::user_mm_dealloc(base, ALLOC_SIZE); assert!(res.is_ok()); - println!("{}", "Successfully run modify types!"); + println!("Successfully run modify types!"); SgxStatus::Success } @@ -252,33 +216,15 @@ fn test_commit_and_uncommit() -> SgxStatus { let res = emm::user_mm_dealloc(0, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let base = emm::user_mm_alloc( - None, - ALLOC_SIZE, - AllocFlags::COMMIT_NOW, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ) - .unwrap(); + let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::user_mm_alloc(&mut options).unwrap(); let res = emm::user_mm_commit(base, ALLOC_SIZE); assert!(res.is_ok()); - let res = emm::user_mm_alloc( - Some(base), - ALLOC_SIZE, - AllocFlags::COMMIT_NOW | AllocFlags::FIXED, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ); + let mut options = EmaOptions::new(base, ALLOC_SIZE, AllocFlags::COMMIT_NOW | AllocFlags::FIXED); + let res = emm::user_mm_alloc(&mut options); + assert!(res == Err(EEXIST)); let res = emm::user_mm_uncommit(base, ALLOC_SIZE); @@ -299,31 +245,25 @@ fn test_commit_and_uncommit() -> SgxStatus { let res = emm::user_mm_uncommit(base, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let base2 = emm::user_mm_alloc( - None, + let mut options = EmaOptions::new( + 0, ALLOC_SIZE, AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ) - .unwrap(); + ); + let base2 = emm::user_mm_alloc(&mut options).unwrap(); assert!(base == base2); let ptr = base2 as *mut u8; unsafe { ptr.write(0xFF); - ptr.offset((ALLOC_SIZE - 1) as isize).write(0xFF); + ptr.add(ALLOC_SIZE - 1).write(0xFF); }; let res = emm::user_mm_dealloc(base2, ALLOC_SIZE); assert!(res.is_ok()); - println!("{}", "Successfully run commit and uncommit!"); + println!("Successfully run commit and uncommit!"); SgxStatus::Success } @@ -337,7 +277,7 @@ fn test_stack_expand() -> SgxStatus { for (idx, item) in buf.iter().enumerate() { assert!(*item == (idx % 256) as u8); } - println!("{}", "Successfully expand stack!"); + println!("Successfully expand stack!"); SgxStatus::Success } @@ -346,22 +286,12 @@ fn test_emm_alloc_dealloc() -> SgxStatus { let res = emm::user_mm_dealloc(0, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let base = emm::user_mm_alloc( - None, - ALLOC_SIZE, - AllocFlags::COMMIT_NOW, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ) - .unwrap(); + let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::user_mm_alloc(&mut options).unwrap(); let res = emm::user_mm_dealloc(base, ALLOC_SIZE); assert!(res.is_ok()); - println!("{}", "Successfully run alloc and dealloc!"); + println!("Successfully run alloc and dealloc!"); SgxStatus::Success } diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs index 7aef93f87..fea20f020 100644 --- a/sgx_trts/src/capi.rs +++ b/sgx_trts/src/capi.rs @@ -17,14 +17,14 @@ use crate::arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}; use crate::call::{ocall, OCallIndex, OcBuffer}; -use crate::emm::alloc::Alloc; +use crate::emm::ema::EmaOptions; use crate::emm::page::AllocFlags; use crate::emm::pfhandler::PfHandler; use crate::emm::range::{ - RangeType, ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, - PAGE_TYPE_MASK, PAGE_TYPE_SHIFT, RM, + ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, PAGE_TYPE_MASK, + PAGE_TYPE_SHIFT, }; -use crate::emm::{rts_mm_commit, rts_mm_uncommit, PageInfo, PageType, ProtFlags}; +use crate::emm::{rts_mm_commit, rts_mm_uncommit, user_mm_alloc, PageInfo, PageType, ProtFlags}; use crate::enclave::{self, is_within_enclave, MmLayout}; use crate::error; use crate::rand::rand; @@ -261,7 +261,7 @@ pub unsafe extern "C" fn sgx_mm_alloc( } } else { PageInfo { - prot: ProtFlags::R | ProtFlags::W, + prot: ProtFlags::RW, typ: page_type, } }; @@ -272,17 +272,11 @@ pub unsafe extern "C" fn sgx_mm_alloc( Some(priv_data) }; - let mut range_manage = RM.get().unwrap().lock(); - match range_manage.alloc( - Some(addr), - size, - alloc_flags, - info, - handler, - priv_data, - RangeType::User, - Alloc::Reserve, - ) { + let addr = if addr > 0 { Some(addr) } else { None }; + let mut options = EmaOptions::new(addr, size, alloc_flags); + options.info(info).handle(handler, priv_data); + + match user_mm_alloc(&options) { Ok(base) => { *out_addr = base as *mut u8; 0 diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index 210ca3a39..d9f39b10f 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -29,6 +29,7 @@ use core::mem::MaybeUninit; use core::ptr::NonNull; use spin::{Mutex, Once}; +use super::ema::EmaOptions; use super::page::AllocFlags; use super::range::{RangeType, RM}; use super::{PageInfo, PageType, ProtFlags}; @@ -49,12 +50,15 @@ const MAX_EMALLOC_SIZE: usize = 0x10000000; const ALLOC_MASK: usize = 1; const SIZE_MASK: usize = !(EXACT_MATCH_INCREMENT - 1); -/// Lowest level: Allocator for static memory -pub static STATIC: Once> = Once::new(); - /// Static memory for allocation static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; +/// Lowest level: Allocator for static memory +static STATIC: Once> = Once::new(); + +/// Second level: Allocator for reserve memory +static RSRV_ALLOCATOR: Once> = Once::new(); + /// Init lowest level static memory allocator pub fn init_static_alloc() { STATIC.call_once(|| { @@ -68,23 +72,20 @@ pub fn init_static_alloc() { }); } -/// Second level: Allocator for reserve memory -pub static RES_ALLOCATOR: Once> = Once::new(); - /// Init reserve memory allocator /// init_reserve_alloc() need to be called after init_static_alloc() pub fn init_reserve_alloc() { - RES_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); + RSRV_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); } -/// Alloc layout memory from reserve memory region -#[derive(Clone, Copy)] -pub struct ResAlloc; +/// AllocType layout memory from reserve memory region +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct RsrvAlloc; -unsafe impl Allocator for ResAlloc { +unsafe impl Allocator for RsrvAlloc { fn allocate(&self, layout: Layout) -> Result, AllocError> { let size = layout.size(); - RES_ALLOCATOR + RSRV_ALLOCATOR .get() .unwrap() .lock() @@ -95,12 +96,12 @@ unsafe impl Allocator for ResAlloc { #[inline] unsafe fn deallocate(&self, ptr: NonNull, _layout: Layout) { - RES_ALLOCATOR.get().unwrap().lock().efree(ptr.addr().get()) + RSRV_ALLOCATOR.get().unwrap().lock().efree(ptr.addr().get()) } } -/// Alloc layout memory from static memory region -#[derive(Clone, Copy)] +/// AllocType layout memory from static memory region +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct StaticAlloc; unsafe impl Allocator for StaticAlloc { @@ -123,11 +124,20 @@ unsafe impl Allocator for StaticAlloc { // Enum for allocator types #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] -pub enum Alloc { - Static, - Reserve, +pub enum AllocType { + Static(StaticAlloc), + Reserve(RsrvAlloc), } +impl AllocType { + pub fn new_static() -> Self { + Self::Static(StaticAlloc) + } + + pub fn new_rsrv() -> Self { + Self::Reserve(RsrvAlloc) + } +} // Chunk manages memory range. // The Chunk structure is filled into the layout before the base pointer. #[derive(Debug)] @@ -381,7 +391,7 @@ impl Reserve { return Ok(self.block_to_payload(block)); }; - // Alloc new block from chunks + // AllocType new block from chunks block = self.alloc_from_chunks(bsize); if block.is_none() { let chunk_size = size_of::(); @@ -455,35 +465,26 @@ impl Reserve { // Here we alloc at least INIT_MEM_SIZE size, // but commit rsize memory, the remaining memory is COMMIT_ON_DEMAND let increment = self.incr_size.max(rsize); - let mut range_manage = RM.get().unwrap().lock(); - let base = range_manage.alloc( - None, - increment + 2 * GUARD_SIZE, - AllocFlags::RESERVED, - PageInfo { + + let mut options = EmaOptions::new(None, increment + 2 * GUARD_SIZE, AllocFlags::RESERVED); + + options + .info(PageInfo { typ: PageType::None, prot: ProtFlags::NONE, - }, - None, - None, - RangeType::User, - Alloc::Static, - )?; - - let base = range_manage.alloc( + }) + .alloc(AllocType::new_static()); + let base = range_manage.alloc(&options, RangeType::User)?; + + let mut options = EmaOptions::new( Some(base + GUARD_SIZE), increment, AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - RangeType::User, - Alloc::Static, - )?; + ); + + options.alloc(AllocType::new_static()); + let base = range_manage.alloc(&options, RangeType::User)?; range_manage.commit(base, rsize, RangeType::User)?; drop(range_manage); diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index d215e5180..8b0b41515 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -23,9 +23,7 @@ use core::ptr::NonNull; use sgx_tlibc_sys::EACCES; use sgx_types::error::OsResult; -use super::alloc::Alloc; -use super::alloc::ResAlloc; -use super::alloc::StaticAlloc; +use super::alloc::AllocType; #[repr(C)] #[derive(Debug)] @@ -33,23 +31,23 @@ pub struct BitArray { bits: usize, bytes: usize, data: *mut u8, - alloc: Alloc, + alloc: AllocType, } impl BitArray { /// Init BitArray with all zero bits - pub fn new(bits: usize, alloc: Alloc) -> OsResult { + pub fn new(bits: usize, alloc: AllocType) -> OsResult { let bytes = (bits + 7) / 8; // FIXME: return error if OOM let data = match alloc { - Alloc::Reserve => { + AllocType::Reserve(allocator) => { // Set bits to all zeros - let data = vec::from_elem_in(0_u8, bytes, ResAlloc).into_boxed_slice(); + let data = vec::from_elem_in(0_u8, bytes, allocator).into_boxed_slice(); Box::into_raw(data) as *mut u8 } - Alloc::Static => { - let data = vec::from_elem_in(0_u8, bytes, StaticAlloc).into_boxed_slice(); + AllocType::Static(allocator) => { + let data = vec::from_elem_in(0_u8, bytes, allocator).into_boxed_slice(); Box::into_raw(data) as *mut u8 } }; @@ -155,21 +153,21 @@ impl BitArray { impl Drop for BitArray { fn drop(&mut self) { match self.alloc { - Alloc::Reserve => { + AllocType::Reserve(allocator) => { // Layout is redundant since interior allocator maintains the allocated size. // Besides, if the bitmap is splitted, the recorded size // in bitmap is not corresponding to allocated layout. let fake_layout: Layout = Layout::new::(); unsafe { let data_ptr = NonNull::new_unchecked(self.data); - ResAlloc.deallocate(data_ptr, fake_layout); + allocator.deallocate(data_ptr, fake_layout); } } - Alloc::Static => { + AllocType::Static(allocator) => { let fake_layout: Layout = Layout::new::(); unsafe { let data_ptr = NonNull::new_unchecked(self.data); - StaticAlloc.deallocate(data_ptr, fake_layout); + allocator.deallocate(data_ptr, fake_layout); } } } diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index 675ab9f9d..aa417117a 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -20,11 +20,11 @@ use crate::emm::{PageInfo, PageRange, PageType, ProtFlags}; use crate::enclave::is_within_enclave; use alloc::boxed::Box; use intrusive_collections::{intrusive_adapter, LinkedListLink, UnsafeRef}; -use sgx_tlibc_sys::{c_void, EACCES, EINVAL}; +use sgx_tlibc_sys::{c_void, EACCES, EFAULT, EINVAL}; use sgx_types::error::OsResult; -use super::alloc::Alloc; -use super::alloc::{ResAlloc, StaticAlloc}; +use super::alloc::AllocType; +use super::alloc::{RsrvAlloc, StaticAlloc}; use super::bitmap::BitArray; use super::ocall; use super::page::AllocFlags; @@ -32,7 +32,7 @@ use super::pfhandler::PfHandler; /// Enclave Management Area #[repr(C)] -pub struct EMA { +pub struct Ema { // page aligned start address start: usize, // bytes, round to page bytes @@ -46,17 +46,32 @@ pub struct EMA { handler: Option, // private data for PF handler priv_data: Option<*mut c_void>, - alloc: Alloc, + alloc: AllocType, // intrusive linkedlist link: LinkedListLink, } +// Implement ema adapter for the operations of intrusive linkedlist +intrusive_adapter!(pub EmaAda = UnsafeRef: Ema { link: LinkedListLink }); + +#[derive(Clone, Copy)] +/// Options for allocating Emas. +pub struct EmaOptions { + pub addr: Option, + pub length: usize, + pub alloc_flags: AllocFlags, + pub alloc: AllocType, + info: PageInfo, + handler: Option, + priv_data: Option<*mut c_void>, +} + // TODO: remove send and sync -unsafe impl Send for EMA {} -unsafe impl Sync for EMA {} +unsafe impl Send for Ema {} +unsafe impl Sync for Ema {} -impl EMA { - /// Initialize EMA node with null eaccept map, +impl Ema { + /// Initialize Emanode with null eaccept map, /// and start address must be page aligned pub fn new( start: usize, @@ -65,10 +80,9 @@ impl EMA { info: PageInfo, handler: Option, priv_data: Option<*mut c_void>, - alloc: Alloc, + alloc: AllocType, ) -> OsResult { - // check alloc flags' eligibility - // AllocFlags::try_from(alloc_flags.bits())?; + // TODO: check alloc flags' eligibility if start != 0 && length != 0 @@ -92,10 +106,26 @@ impl EMA { } } + pub fn new_options(options: &EmaOptions) -> OsResult { + ensure!(options.addr.is_some(), EINVAL); + + Ok(Self { + start: options.addr.unwrap(), + length: options.length, + alloc_flags: options.alloc_flags, + info: options.info, + eaccept_map: None, + handler: options.handler, + priv_data: options.priv_data, + link: LinkedListLink::new(), + alloc: options.alloc, + }) + } + /// Split current ema at specified address, return a new allocated ema /// corresponding to the memory at the range of [addr, end). /// And the current ema manages the memory at the range of [start, addr). - pub fn split(&mut self, addr: usize) -> OsResult<*mut EMA> { + pub fn split(&mut self, addr: usize) -> OsResult<*mut Ema> { let l_start = self.start; let l_length = addr - l_start; @@ -110,40 +140,40 @@ impl EMA { None => None, }; - // Initialize EMA with same allocator - let new_ema: *mut EMA = match self.alloc { - Alloc::Reserve => { + // Initialize Emawith same allocator + let new_ema: *mut Ema = match self.alloc { + AllocType::Reserve(allocator) => { let mut ema = Box::new_in( - EMA::new( + Ema::new( self.start, self.length, self.alloc_flags, self.info, self.handler, self.priv_data, - Alloc::Reserve, + AllocType::new_rsrv(), ) .unwrap(), - ResAlloc, + allocator, ); ema.start = r_start; ema.length = r_length; ema.eaccept_map = new_bitarray; Box::into_raw(ema) } - Alloc::Static => { + AllocType::Static(allocator) => { let mut ema = Box::new_in( - EMA::new( + Ema::new( self.start, self.length, self.alloc_flags, self.info, self.handler, self.priv_data, - Alloc::Static, + AllocType::new_static(), ) .unwrap(), - StaticAlloc, + allocator, ); ema.start = r_start; ema.length = r_length; @@ -168,13 +198,13 @@ impl EMA { // Allocate new eaccept_map for COMMIT_ON_DEMAND and COMMIT_NOW if self.eaccept_map.is_none() { let eaccept_map = match self.alloc { - Alloc::Reserve => { + AllocType::Reserve(_allocator) => { let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, Alloc::Reserve)? + BitArray::new(page_num, AllocType::new_rsrv())? } - Alloc::Static => { + AllocType::Static(_allocator) => { let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, Alloc::Static)? + BitArray::new(page_num, AllocType::new_static())? } }; self.eaccept_map = Some(eaccept_map); @@ -212,7 +242,7 @@ impl EMA { /// Check the prerequisites of ema commitment pub fn commit_check(&self) -> OsResult { - if !self.info.prot.intersects(ProtFlags::R | ProtFlags::W) { + if !self.info.prot.intersects(ProtFlags::RW) { return Err(EACCES); } @@ -244,7 +274,7 @@ impl EMA { let info = PageInfo { typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W | ProtFlags::PENDING, + prot: ProtFlags::RW | ProtFlags::PENDING, }; let pages = PageRange::new(start, length / crate::arch::SE_PAGE_SIZE, info)?; @@ -470,7 +500,7 @@ impl EMA { return Ok(()); } - if (info.prot != (ProtFlags::R | ProtFlags::W)) || (info.typ != PageType::Reg) { + if (info.prot != ProtFlags::RW) || (info.typ != PageType::Reg) { return Err(EACCES); } @@ -567,13 +597,13 @@ impl EMA { pub fn set_eaccept_map_full(&mut self) -> OsResult { if self.eaccept_map.is_none() { let mut eaccept_map = match self.alloc { - Alloc::Reserve => { + AllocType::Reserve(_allocator) => { let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, Alloc::Reserve)? + BitArray::new(page_num, AllocType::new_rsrv())? } - Alloc::Static => { + AllocType::Static(_allocator) => { let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, Alloc::Static)? + BitArray::new(page_num, AllocType::new_static())? } }; eaccept_map.set_full(); @@ -593,7 +623,7 @@ impl EMA { } /// Obtain the allocator of ema - pub fn allocator(&self) -> Alloc { + pub fn allocator(&self) -> AllocType { self.alloc } @@ -610,8 +640,85 @@ impl EMA { } } -// Implement ema adapter for the operations of intrusive linkedlist -intrusive_adapter!(pub EmaAda = UnsafeRef: EMA { link: LinkedListLink }); +impl EmaOptions { + /// Creates new options for allocating the Emas + pub fn new(addr: Option, length: usize, alloc_flags: AllocFlags) -> Self { + Self { + addr, + length, + alloc_flags, + info: PageInfo { + typ: PageType::Reg, + prot: ProtFlags::RW, + }, + handler: None, + priv_data: None, + alloc: AllocType::new_rsrv(), + } + } + + /// Resets the base address of allocated Emas. + pub fn addr(&mut self, addr: usize) -> &mut Self { + self.addr = Some(addr); + self + } + + /// Sets the page info of allocated Emas. + /// + /// The default value is `PageInfo { typ: PageType::Reg, prot: ProtFlags::RW }`. + pub fn info(&mut self, info: PageInfo) -> &mut Self { + self.info = info; + self + } + + /// Sets the customized page fault handler and private data of allocated Emas. + /// + /// The default value is `handler: None, priv_data: None`. + pub fn handle( + &mut self, + handler: Option, + priv_data: Option<*mut c_void>, + ) -> &mut Self { + self.handler = handler; + self.priv_data = priv_data; + self + } + + /// The method can not be exposed to User. + /// Sets the inner allocate method of allocated Emas. + /// + /// If `alloc` is set as `AllocType::Reserve`, the Ema will be allocated + /// at reserve memory region (commited pages in user region). + /// If `alloc` is set as `AllocType::Static`, the Ema will be allocated + /// at static memory region (a small static memory). + /// + /// The default value is `AllocType::Reserve`. + pub(crate) fn alloc(&mut self, alloc: AllocType) -> &mut Self { + self.alloc = alloc; + self + } +} + +impl Ema { + pub fn allocate(options: &EmaOptions, apply_now: bool) -> OsResult> { + ensure!(options.addr.is_some(), EFAULT); + let mut new_ema = match options.alloc { + AllocType::Reserve(allocator) => { + let new_ema = Box::::new_in(Ema::new_options(options)?, allocator); + unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } + } + AllocType::Static(allocator) => { + let new_ema = + Box::::new_in(Ema::new_options(options)?, allocator); + unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } + } + }; + if apply_now { + new_ema.alloc()?; + } + Ok(new_ema) + } +} // pub struct EmaRange<'a> { // pub cursor: CursorMut<'a, EmaAda>, diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs index aea2d0d93..c6d7e6bfb 100644 --- a/sgx_trts/src/emm/init.rs +++ b/sgx_trts/src/emm/init.rs @@ -36,11 +36,14 @@ cfg_if! { mod hw { use crate::arch::{self, Layout, LayoutEntry}; use crate::elf::program::Type; - use crate::emm::alloc::Alloc; + use crate::emm::ema::EmaOptions; use crate::emm::layout::LayoutTable; use crate::emm::page::AllocFlags; - use crate::emm::range::{RangeType, EMA_PROT_MASK, RM}; - use crate::emm::{PageInfo, PageType, ProtFlags}; + use crate::emm::range::{mm_init_static_region, EMA_PROT_MASK}; + use crate::emm::{ + rts_mm_alloc, rts_mm_commit, rts_mm_dealloc, rts_mm_modify_perms, PageInfo, PageType, + ProtFlags, + }; use crate::enclave::parse; use crate::enclave::MmLayout; use sgx_types::error::{SgxResult, SgxStatus}; @@ -84,23 +87,16 @@ mod hw { // TODO: not sure get_enclave_base() equal to elrange_base or image_base let addr = MmLayout::image_base() + rva; let size = (entry.page_count << arch::SE_PAGE_SHIFT) as usize; - let mut range_manage = RM.get().unwrap().lock(); // entry is guard page or has EREMOVE, build a reserved ema if (entry.si_flags == 0) || (entry.attributes & arch::PAGE_ATTR_EREMOVE != 0) { - range_manage - .init_static_region( - addr, - size, - AllocFlags::RESERVED | AllocFlags::SYSTEM, - PageInfo { - typ: PageType::None, - prot: ProtFlags::NONE, - }, - None, - None, - ) - .map_err(|_| SgxStatus::Unexpected)?; + let mut options = + EmaOptions::new(Some(addr), size, AllocFlags::RESERVED | AllocFlags::SYSTEM); + options.info(PageInfo { + typ: PageType::None, + prot: ProtFlags::NONE, + }); + mm_init_static_region(&options).map_err(|_| SgxStatus::Unexpected)?; return Ok(()); } @@ -110,23 +106,14 @@ mod hw { if post_remove { // TODO: maybe AllocFlags need more flags or PageType is not None - range_manage - .init_static_region( - addr, - size, - AllocFlags::SYSTEM, - PageInfo { - typ: PageType::None, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - ) - .map_err(|_| SgxStatus::Unexpected)?; - - range_manage - .dealloc(addr, size, RangeType::Rts) - .map_err(|_| SgxStatus::Unexpected)?; + let mut options = EmaOptions::new(Some(addr), size, AllocFlags::SYSTEM); + options.info(PageInfo { + typ: PageType::None, + prot: ProtFlags::RW, + }); + mm_init_static_region(&options).map_err(|_| SgxStatus::Unexpected)?; + + rts_mm_dealloc(addr, size).map_err(|_| SgxStatus::Unexpected)?; } if post_add { @@ -139,25 +126,16 @@ mod hw { AllocFlags::GROWSUP }; - // TODO: revise alloc and not use int - range_manage - .alloc( - Some(addr), - size, - AllocFlags::COMMIT_ON_DEMAND - | commit_direction - | AllocFlags::SYSTEM - | AllocFlags::FIXED, - PageInfo { - typ: PageType::Reg, - prot: ProtFlags::R | ProtFlags::W, - }, - None, - None, - RangeType::Rts, - Alloc::Reserve, - ) - .map_err(|_| SgxStatus::Unexpected)?; + let options = EmaOptions::new( + Some(addr), + size, + AllocFlags::COMMIT_ON_DEMAND + | commit_direction + | AllocFlags::SYSTEM + | AllocFlags::FIXED, + ); + + rts_mm_alloc(&options).map_err(|_| SgxStatus::Unexpected)?; } else if static_min { let info = if entry.id == arch::LAYOUT_ID_TCS { PageInfo { @@ -172,9 +150,10 @@ mod hw { ), } }; - range_manage - .init_static_region(addr, size, AllocFlags::SYSTEM, info, None, None) - .map_err(|_| SgxStatus::Unexpected)?; + let mut options = EmaOptions::new(Some(addr), size, AllocFlags::SYSTEM); + + options.info(info); + mm_init_static_region(&options).map_err(|_| SgxStatus::Unexpected)?; } Ok(()) @@ -187,10 +166,7 @@ mod hw { .check_dyn_range(addr, count, None) .ok_or(SgxStatus::InvalidParameter)?; - let mut range_manage = RM.get().unwrap().lock(); - range_manage - .commit(addr, count << arch::SE_PAGE_SHIFT, RangeType::Rts) - .map_err(|_| SgxStatus::Unexpected)?; + rts_mm_commit(addr, count << arch::SE_PAGE_SHIFT).map_err(|_| SgxStatus::Unexpected)?; Ok(()) } @@ -200,7 +176,6 @@ mod hw { let text_relo = parse::has_text_relo()?; let base = MmLayout::image_base(); - let mut range_manage = RM.get().unwrap().lock(); for phdr in elf.program_iter() { let typ = phdr.get_type().unwrap_or(Type::Null); if typ == Type::Load && text_relo && !phdr.flags().is_write() { @@ -218,9 +193,7 @@ mod hw { } let prot = ProtFlags::from_bits_truncate(perm as u8); - range_manage - .modify_perms(start, size, prot, RangeType::Rts) - .map_err(|_| SgxStatus::Unexpected)?; + rts_mm_modify_perms(start, size, prot).map_err(|_| SgxStatus::Unexpected)?; } if typ == Type::GnuRelro { let start = base + trim_to_page!(phdr.virtual_addr() as usize); @@ -229,8 +202,7 @@ mod hw { let size = end - start; if size > 0 { - range_manage - .modify_perms(start, size, ProtFlags::R, RangeType::Rts) + rts_mm_modify_perms(start, size, ProtFlags::R) .map_err(|_| SgxStatus::Unexpected)?; } } @@ -245,9 +217,7 @@ mod hw { let start = base + unsafe { layout.entry.rva as usize }; let size = unsafe { layout.entry.page_count as usize } << arch::SE_PAGE_SHIFT; - range_manage - .modify_perms(start, size, ProtFlags::R, RangeType::Rts) - .map_err(|_| SgxStatus::Unexpected)?; + rts_mm_modify_perms(start, size, ProtFlags::R).map_err(|_| SgxStatus::Unexpected)?; } Ok(()) } @@ -273,20 +243,12 @@ mod hw { perm |= ProtFlags::X; } - let mut range_manage = RM.get().unwrap().lock(); - range_manage - .init_static_region( - start, - end - start, - AllocFlags::SYSTEM, - PageInfo { - typ: PageType::Reg, - prot: perm, - }, - None, - None, - ) - .map_err(|_| SgxStatus::Unexpected)?; + let mut options = EmaOptions::new(Some(start), end - start, AllocFlags::SYSTEM); + options.info(PageInfo { + typ: PageType::Reg, + prot: perm, + }); + mm_init_static_region(&options).map_err(|_| SgxStatus::Unexpected)?; } } diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index b070934a2..44eef03c2 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -28,7 +28,7 @@ pub(crate) mod pfhandler; pub(crate) mod range; pub(crate) mod tcs; -pub use ocall::{alloc_ocall, modify_ocall}; +pub use ema::EmaOptions; pub use page::{AllocFlags, PageInfo, PageRange, PageType, ProtFlags}; pub use pfhandler::{PfHandler, PfInfo, Pfec, PfecBits}; diff --git a/sgx_trts/src/emm/page.rs b/sgx_trts/src/emm/page.rs index ea239bb1b..1dafcd75f 100644 --- a/sgx_trts/src/emm/page.rs +++ b/sgx_trts/src/emm/page.rs @@ -49,9 +49,6 @@ impl_enum! { } } -// ProtFlags may have richer meaning compared to ProtFlags -// ProtFlags and AllocFlags are confused to developer -// PageInfo->flags should change to PageInfo->prot impl_bitflags! { #[repr(C)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -65,7 +62,7 @@ impl_bitflags! { const PR = 0x20; const RW = Self::R.bits() | Self::W.bits(); const RX = Self::R.bits() | Self::X.bits(); - const RWX = Self::R.bits() | Self::W.bits() | Self::X.bits(); + const RWX = Self::R.bits() | Self::W.bits() | Self::X.bits(); } } diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/range.rs index baa2e6ce0..757858377 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/range.rs @@ -17,21 +17,20 @@ use crate::{ arch::SE_PAGE_SIZE, - emm::{PageInfo, PageType, ProtFlags}, + emm::{PageType, ProtFlags}, enclave::{is_within_enclave, is_within_rts_range, is_within_user_range, MmLayout}, sync::SpinReentrantMutex, }; use alloc::boxed::Box; use intrusive_collections::{linked_list::CursorMut, LinkedList, UnsafeRef}; -use sgx_tlibc_sys::{c_void, EEXIST, EINVAL, ENOMEM, EPERM}; +use sgx_tlibc_sys::{EEXIST, EINVAL, ENOMEM, EPERM}; use sgx_types::error::OsResult; use spin::Once; use super::{ - alloc::{Alloc, ResAlloc, StaticAlloc}, - ema::{EmaAda, EMA}, + alloc::AllocType, + ema::{Ema, EmaAda, EmaOptions}, page::AllocFlags, - pfhandler::PfHandler, }; pub const ALLOC_FLAGS_SHIFT: usize = 0; @@ -45,32 +44,21 @@ pub const ALLIGNMENT_MASK: usize = 0xFF << ALLIGNMENT_SHIFT; pub const EMA_PROT_MASK: usize = 0x7; -pub static RM: Once> = Once::new(); +pub(crate) static RM: Once> = Once::new(); /// Initialize range management pub fn init_range_manage() { RM.call_once(|| SpinReentrantMutex::new(RangeManage::new())); } -pub fn user_mm_alloc( - addr: Option, - size: usize, - alloc_flags: AllocFlags, - info: PageInfo, - handler: Option, - priv_data: Option<*mut c_void>, -) -> OsResult { +pub fn mm_init_static_region(options: &EmaOptions) -> OsResult { let mut range_manage = RM.get().unwrap().lock(); - range_manage.alloc( - addr, - size, - alloc_flags, - info, - handler, - priv_data, - RangeType::User, - Alloc::Reserve, - ) + range_manage.init_static_region(options) +} + +pub fn user_mm_alloc(options: &EmaOptions) -> OsResult { + let mut range_manage = RM.get().unwrap().lock(); + range_manage.alloc(options, RangeType::User) } pub fn user_mm_dealloc(addr: usize, size: usize) -> OsResult { @@ -98,25 +86,9 @@ pub fn user_mm_modify_perms(addr: usize, size: usize, prot: ProtFlags) -> OsResu range_manage.modify_perms(addr, size, prot, RangeType::User) } -pub fn rts_mm_alloc( - addr: Option, - size: usize, - alloc_flags: AllocFlags, - info: PageInfo, - handler: Option, - priv_data: Option<*mut c_void>, -) -> OsResult { +pub fn rts_mm_alloc(options: &EmaOptions) -> OsResult { let mut range_manage = RM.get().unwrap().lock(); - range_manage.alloc( - addr, - size, - alloc_flags, - info, - handler, - priv_data, - RangeType::Rts, - Alloc::Reserve, - ) + range_manage.alloc(options, RangeType::Rts) } pub fn rts_mm_dealloc(addr: usize, size: usize) -> OsResult { @@ -168,64 +140,46 @@ impl RangeManage { // Reserve memory range for allocations created // by the RTS enclave loader at fixed address ranges - pub fn init_static_region( - &mut self, - addr: usize, - size: usize, - alloc_flags: AllocFlags, - info: PageInfo, - handler: Option, - priv_data: Option<*mut c_void>, - ) -> OsResult { - ensure!( - addr != 0 && size != 0 && is_within_enclave(addr as *const u8, size), - EINVAL - ); + pub fn init_static_region(&mut self, options: &EmaOptions) -> OsResult { + ensure!(options.addr.is_some(), EINVAL); + + // ensure!( + // options.addr != None && size != 0 && is_within_enclave(addr as *const u8, size), + // EINVAL + // ); let mut next_ema = self - .find_free_region_at(addr, size, RangeType::Rts) + .find_free_region_at(options.addr.unwrap(), options.length, RangeType::Rts) .ok_or(EINVAL)?; - let mut new_ema = Box::::new_in( - EMA::new( - addr, - size, - alloc_flags, - info, - handler, - priv_data, - Alloc::Reserve, - )?, - ResAlloc, - ); + let mut new_ema = Ema::allocate(options, false)?; - if !alloc_flags.contains(AllocFlags::RESERVED) { + if !options.alloc_flags.contains(AllocFlags::RESERVED) { new_ema.set_eaccept_map_full()?; } - let new_ema_ref = unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) }; - next_ema.insert_before(new_ema_ref); + next_ema.insert_before(new_ema); Ok(()) } - // Clear the EMAs in charging of [start, end) memory region, + // Clear the Emas in charging of [start, end) memory region, // return next ema cursor fn clear_reserved_emas( &mut self, start: usize, end: usize, typ: RangeType, - alloc: Alloc, + alloc: AllocType, ) -> Option> { let (mut cursor, ema_num) = self.search_ema_range(start, end, typ, true)?; - let start_ema_ptr = cursor.get().unwrap() as *const EMA; + let start_ema_ptr = cursor.get().unwrap() as *const Ema; - // Check EMA attributes + // Check Emaattributes let mut count = ema_num; while count != 0 { let ema = cursor.get().unwrap(); - // EMA must be reserved and can not manage internal memory region + // Emamust be reserved and can not manage internal memory region if !ema.flags().contains(AllocFlags::RESERVED) || ema.allocator() != alloc { return None; } @@ -248,18 +202,10 @@ impl RangeManage { } /// Allocate a new memory region in enclave address space (ELRANGE). - pub fn alloc( - &mut self, - addr: Option, - size: usize, - alloc_flags: AllocFlags, - info: PageInfo, - handler: Option, - priv_data: Option<*mut c_void>, - typ: RangeType, - alloc: Alloc, - ) -> OsResult { - let addr = addr.unwrap_or(0); + pub fn alloc(&mut self, options: &EmaOptions, typ: RangeType) -> OsResult { + let addr = options.addr.unwrap_or(0); + let size = options.length; + let end = addr + size; // Default align is 12 let align_flag = 12; @@ -281,13 +227,13 @@ impl RangeManage { let mut alloc_next_ema: Option> = None; if addr > 0 { - let is_fixed_alloc = alloc_flags.contains(AllocFlags::FIXED); + let is_fixed_alloc = options.alloc_flags.contains(AllocFlags::FIXED); // FIXME: search_ema_range implicitly contains splitting ema - let range = self.search_ema_range(addr, addr + size, typ, false); + let range = self.search_ema_range(addr, end, typ, false); match range { // exist in emas list - Some(_) => match self.clear_reserved_emas(addr, addr + size, typ, alloc) { + Some(_) => match self.clear_reserved_emas(addr, end, typ, options.alloc) { Some(ema) => { alloc_addr = Some(addr); alloc_next_ema = Some(ema); @@ -316,46 +262,12 @@ impl RangeManage { alloc_next_ema = Some(next_ema); } - // let (free_addr, mut next_ema) = self.find_free_region(size, 1 << align_flag, typ)?; - - let new_ema_ref = match alloc { - Alloc::Reserve => { - let mut new_ema = Box::::new_in( - EMA::new( - alloc_addr.unwrap(), - size, - alloc_flags, - info, - handler, - priv_data, - Alloc::Reserve, - )?, - ResAlloc, - ); - new_ema.alloc()?; - - unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } - } - Alloc::Static => { - let mut new_ema = Box::::new_in( - EMA::new( - alloc_addr.unwrap(), - size, - alloc_flags, - info, - handler, - priv_data, - Alloc::Static, - )?, - StaticAlloc, - ); - new_ema.alloc()?; - - unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } - } - }; + let mut ema_options = *options; + ema_options.addr(alloc_addr.unwrap()); + + let new_ema = Ema::allocate(&ema_options, true)?; - alloc_next_ema.unwrap().insert_before(new_ema_ref); + alloc_next_ema.unwrap().insert_before(new_ema); Ok(alloc_addr.unwrap()) } @@ -365,7 +277,7 @@ impl RangeManage { let (mut cursor, ema_num) = self .search_ema_range(addr, addr + size, typ, true) .ok_or(EINVAL)?; - let start_ema_ptr = cursor.get().unwrap() as *const EMA; + let start_ema_ptr = cursor.get().unwrap() as *const Ema; let mut count = ema_num; while count != 0 { @@ -399,14 +311,13 @@ impl RangeManage { let mut ema = cursor.remove().unwrap(); ema.dealloc()?; - // Drop inner EMA + // Drop inner Ema match ema.allocator() { - Alloc::Reserve => { - let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), ResAlloc) }; + AllocType::Reserve(allocator) => { + let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), allocator) }; } - Alloc::Static => { - let _ema_box = - unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), StaticAlloc) }; + AllocType::Static(allocator) => { + let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), allocator) }; } } ema_num -= 1; @@ -459,7 +370,7 @@ impl RangeManage { let (mut cursor, ema_num) = self .search_ema_range(addr, addr + size, typ, true) .ok_or(EINVAL)?; - let start_ema_ptr = cursor.get().unwrap() as *const EMA; + let start_ema_ptr = cursor.get().unwrap() as *const Ema; let mut count = ema_num; while count != 0 { @@ -489,7 +400,7 @@ impl RangeManage { let (mut cursor, ema_num) = self .search_ema_range(addr, addr + size, typ, true) .ok_or(EINVAL)?; - let start_ema_ptr = cursor.get().unwrap() as *const EMA; + let start_ema_ptr = cursor.get().unwrap() as *const Ema; let mut count = ema_num; while count != 0 { @@ -540,7 +451,7 @@ impl RangeManage { let mut curr_ema = cursor.get().unwrap(); - let mut start_ema_ptr = curr_ema as *const EMA; + let mut start_ema_ptr = curr_ema as *const Ema; let mut emas_num = 0; let mut prev_end = curr_ema.start(); @@ -557,7 +468,7 @@ impl RangeManage { cursor.move_next(); } - let mut end_ema_ptr = curr_ema as *const EMA; + let mut end_ema_ptr = curr_ema as *const Ema; // Spliting start ema let mut start_cursor = match typ { @@ -570,11 +481,11 @@ impl RangeManage { // Problem may exist, need to check!! if ema_start < start { - let right_ema = curr_ema.split(start).unwrap() as *const EMA; + let right_ema = curr_ema.split(start).unwrap() as *const Ema; let right_ema_ref = unsafe { UnsafeRef::from_raw(right_ema) }; start_cursor.insert_after(right_ema_ref); start_cursor.move_next(); - start_ema_ptr = start_cursor.get().unwrap() as *const EMA; + start_ema_ptr = start_cursor.get().unwrap() as *const Ema; } if emas_num == 1 { diff --git a/sgx_trts/src/emm/tcs.rs b/sgx_trts/src/emm/tcs.rs index 27aee3733..9675261dd 100644 --- a/sgx_trts/src/emm/tcs.rs +++ b/sgx_trts/src/emm/tcs.rs @@ -64,7 +64,7 @@ pub fn mktcs(mk_tcs: NonNull) -> SgxResult { mod hw { use crate::arch::{self, Layout, Tcs}; use crate::emm::page::PageType; - use crate::emm::range::{RangeType, RM}; + use crate::emm::{rts_mm_commit, rts_mm_modify_type}; use crate::enclave::MmLayout; use crate::tcs::list; use core::ptr; @@ -94,10 +94,7 @@ mod hw { if unsafe { layout.entry.attributes & arch::PAGE_ATTR_DYN_THREAD } != 0 { let addr = base + unsafe { layout.entry.rva as usize } + offset; let size = unsafe { layout.entry.page_count } << arch::SE_PAGE_SHIFT; - let mut range_manage = RM.get().unwrap().lock(); - range_manage - .commit(addr, size as usize, RangeType::Rts) - .map_err(|_| SgxStatus::Unexpected)?; + rts_mm_commit(addr, size as usize).map_err(|_| SgxStatus::Unexpected)?; } } } @@ -118,14 +115,7 @@ mod hw { tc.ofsbase = tcs_ptr + tc.ofsbase - base as u64; tc.ogsbase = tcs_ptr + tc.ogsbase - base as u64; - let mut range_manage = RM.get().unwrap().lock(); - range_manage - .modify_type( - tcs.as_ptr() as usize, - arch::SE_PAGE_SIZE, - PageType::Tcs, - RangeType::Rts, - ) + rts_mm_modify_type(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE, PageType::Tcs) .map_err(|_| SgxStatus::Unexpected)?; Ok(()) diff --git a/sgx_trts/src/enclave/uninit.rs b/sgx_trts/src/enclave/uninit.rs index 23f4ffb38..d59e5931b 100644 --- a/sgx_trts/src/enclave/uninit.rs +++ b/sgx_trts/src/enclave/uninit.rs @@ -16,7 +16,7 @@ // under the License.. use crate::arch; -use crate::emm::range::{RangeType, RM}; +use crate::emm::rts_mm_dealloc; use crate::enclave::state::{self, State}; use crate::enclave::{atexit, parse}; use crate::tcs::{list, ThreadControl}; @@ -82,12 +82,9 @@ pub fn rtuninit(tc: ThreadControl) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] { if SysFeatures::get().is_edmm() { - let mut range_manage = RM.get().unwrap().lock(); - let mut list_guard = list::TCS_LIST.lock(); for tcs in list_guard.iter_mut().filter(|&t| !ptr::eq(t.as_ptr(), tcs)) { - let result = - range_manage.dealloc(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE, RangeType::Rts); + let result = rts_mm_dealloc(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE); if result.is_err() { state::set_state(State::Crashed); bail!(SgxStatus::Unexpected); From aa1fc66d01354353d11b5fc84b597b636cf33bce Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Wed, 27 Sep 2023 16:04:57 +0800 Subject: [PATCH 15/20] Remove range-type related methods --- samplecode/emm/enclave/src/lib.rs | 88 ++++++------ sgx_rsrvmm/src/rsrvmm/area.rs | 4 +- sgx_rsrvmm/src/rsrvmm/mod.rs | 2 +- sgx_trts/src/capi.rs | 35 ++++- sgx_trts/src/emm/alloc.rs | 12 +- sgx_trts/src/emm/ema.rs | 60 ++++---- sgx_trts/src/emm/init.rs | 21 ++- sgx_trts/src/emm/mod.rs | 12 +- sgx_trts/src/emm/pfhandler.rs | 10 +- sgx_trts/src/emm/tcs.rs | 6 +- sgx_trts/src/emm/{range.rs => vmmgr.rs} | 181 +++++++++--------------- sgx_trts/src/enclave/uninit.rs | 4 +- 12 files changed, 208 insertions(+), 227 deletions(-) rename sgx_trts/src/emm/{range.rs => vmmgr.rs} (81%) diff --git a/samplecode/emm/enclave/src/lib.rs b/samplecode/emm/enclave/src/lib.rs index 176ed5b47..0bc3aae01 100644 --- a/samplecode/emm/enclave/src/lib.rs +++ b/samplecode/emm/enclave/src/lib.rs @@ -69,11 +69,11 @@ pub extern "C" fn permission_pfhandler(info: &mut PfInfo, priv_data: *mut c_void let prot = ProtFlags::from_bits(pd.access as u8).unwrap(); let rw_bit = unsafe { pd.pf.pfec.bits.rw() }; if (rw_bit == 1) && (prot == ProtFlags::W) { - if emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, ProtFlags::W | ProtFlags::R).is_err() { + if emm::mm_modify_perms(addr, SE_PAGE_SIZE, ProtFlags::W | ProtFlags::R).is_err() { panic!() }; } else if (rw_bit == 0) && prot.contains(ProtFlags::R) { - if emm::user_mm_modify_perms(addr, SE_PAGE_SIZE, prot).is_err() { + if emm::mm_modify_perms(addr, SE_PAGE_SIZE, prot).is_err() { panic!() }; } else { @@ -87,12 +87,12 @@ pub extern "C" fn permission_pfhandler(info: &mut PfInfo, priv_data: *mut c_void fn test_modify_perms() -> SgxStatus { let mut pd = PfData::default(); // example 1: - let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + let mut options = EmaOptions::new(None, ALLOC_SIZE, AllocFlags::COMMIT_NOW); options.handle( Some(permission_pfhandler), Some(&mut pd as *mut PfData as *mut c_void), ); - let base = emm::user_mm_alloc(&mut options).unwrap(); + let base = emm::mm_alloc_user(&mut options).unwrap(); let data = unsafe { (base as *const u8).read() }; assert!(data == 0); @@ -104,7 +104,7 @@ fn test_modify_perms() -> SgxStatus { // write success without PF assert!(unsafe { pd.pf.pfec.errcd } == 0); - let res = emm::user_mm_modify_perms(base, ALLOC_SIZE / 2, ProtFlags::R); + let res = emm::mm_modify_perms(base, ALLOC_SIZE / 2, ProtFlags::R); assert!(res.is_ok()); pd.access = ProtFlags::R.bits() as i32; @@ -156,55 +156,55 @@ fn test_dynamic_expand_tcs() -> SgxStatus { #[no_mangle] fn test_modify_types() -> SgxStatus { // example 1: - let mut options = EmaOptions::new(0, SE_PAGE_SIZE, AllocFlags::COMMIT_NOW); - let base = emm::user_mm_alloc(&mut options).unwrap(); + let mut options = EmaOptions::new(None, SE_PAGE_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::mm_alloc_user(&mut options).unwrap(); - let res = emm::user_mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); + let res = emm::mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); assert!(res.is_ok()); - let res = emm::user_mm_uncommit(base, SE_PAGE_SIZE); + let res = emm::mm_uncommit(base, SE_PAGE_SIZE); assert!(res.is_ok()); // example 2: - let mut options = EmaOptions::new(0, SE_PAGE_SIZE, AllocFlags::COMMIT_NOW); - let base = emm::user_mm_alloc(&mut options).unwrap(); + let mut options = EmaOptions::new(None, SE_PAGE_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::mm_alloc_user(&mut options).unwrap(); - let res = emm::user_mm_modify_perms(base, SE_PAGE_SIZE, ProtFlags::NONE); + let res = emm::mm_modify_perms(base, SE_PAGE_SIZE, ProtFlags::NONE); assert!(res.is_ok()); - let res = emm::user_mm_uncommit(base, SE_PAGE_SIZE); + let res = emm::mm_uncommit(base, SE_PAGE_SIZE); assert!(res.is_ok()); // example 3: - let res = emm::user_mm_dealloc(0, ALLOC_SIZE); + let res = emm::mm_dealloc(0, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); - let base = emm::user_mm_alloc(&mut options).unwrap(); + let mut options = EmaOptions::new(None, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::mm_alloc_user(&mut options).unwrap(); - let res = emm::user_mm_modify_type(base + SE_PAGE_SIZE, SE_PAGE_SIZE, PageType::Frist); + let res = emm::mm_modify_type(base + SE_PAGE_SIZE, SE_PAGE_SIZE, PageType::Frist); assert!(res == Err(EPERM)); - let res = emm::user_mm_modify_perms( + let res = emm::mm_modify_perms( base + SE_PAGE_SIZE, SE_PAGE_SIZE, ProtFlags::R | ProtFlags::X, ); assert!(res.is_ok()); - let res = emm::user_mm_modify_type(base + SE_PAGE_SIZE, SE_PAGE_SIZE, PageType::Tcs); + let res = emm::mm_modify_type(base + SE_PAGE_SIZE, SE_PAGE_SIZE, PageType::Tcs); assert!(res == Err(EACCES)); - let res = emm::user_mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); + let res = emm::mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); assert!(res.is_ok()); - let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + let res = emm::mm_uncommit(base, ALLOC_SIZE); assert!(res.is_ok()); - let res = emm::user_mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); + let res = emm::mm_modify_type(base, SE_PAGE_SIZE, PageType::Tcs); assert!(res == Err(EACCES)); - let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + let res = emm::mm_dealloc(base, ALLOC_SIZE); assert!(res.is_ok()); println!("Successfully run modify types!"); @@ -213,44 +213,48 @@ fn test_modify_types() -> SgxStatus { #[no_mangle] fn test_commit_and_uncommit() -> SgxStatus { - let res = emm::user_mm_dealloc(0, ALLOC_SIZE); + let res = emm::mm_dealloc(0, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); - let base = emm::user_mm_alloc(&mut options).unwrap(); + let mut options = EmaOptions::new(None, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::mm_alloc_user(&mut options).unwrap(); - let res = emm::user_mm_commit(base, ALLOC_SIZE); + let res = emm::mm_commit(base, ALLOC_SIZE); assert!(res.is_ok()); - let mut options = EmaOptions::new(base, ALLOC_SIZE, AllocFlags::COMMIT_NOW | AllocFlags::FIXED); - let res = emm::user_mm_alloc(&mut options); + let mut options = EmaOptions::new( + Some(base), + ALLOC_SIZE, + AllocFlags::COMMIT_NOW | AllocFlags::FIXED, + ); + let res = emm::mm_alloc_user(&mut options); assert!(res == Err(EEXIST)); - let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + let res = emm::mm_uncommit(base, ALLOC_SIZE); assert!(res.is_ok()); - let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + let res = emm::mm_uncommit(base, ALLOC_SIZE); assert!(res.is_ok()); - let res = emm::user_mm_commit(base, ALLOC_SIZE); + let res = emm::mm_commit(base, ALLOC_SIZE); assert!(res.is_ok()); - let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + let res = emm::mm_dealloc(base, ALLOC_SIZE); assert!(res.is_ok()); - let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + let res = emm::mm_dealloc(base, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let res = emm::user_mm_uncommit(base, ALLOC_SIZE); + let res = emm::mm_uncommit(base, ALLOC_SIZE); assert!(res == Err(EINVAL)); let mut options = EmaOptions::new( - 0, + None, ALLOC_SIZE, AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED, ); - let base2 = emm::user_mm_alloc(&mut options).unwrap(); + let base2 = emm::mm_alloc_user(&mut options).unwrap(); assert!(base == base2); @@ -260,7 +264,7 @@ fn test_commit_and_uncommit() -> SgxStatus { ptr.add(ALLOC_SIZE - 1).write(0xFF); }; - let res = emm::user_mm_dealloc(base2, ALLOC_SIZE); + let res = emm::mm_dealloc(base2, ALLOC_SIZE); assert!(res.is_ok()); println!("Successfully run commit and uncommit!"); @@ -283,13 +287,13 @@ fn test_stack_expand() -> SgxStatus { #[no_mangle] fn test_emm_alloc_dealloc() -> SgxStatus { - let res = emm::user_mm_dealloc(0, ALLOC_SIZE); + let res = emm::mm_dealloc(0, ALLOC_SIZE); assert!(res == Err(EINVAL)); - let mut options = EmaOptions::new(0, ALLOC_SIZE, AllocFlags::COMMIT_NOW); - let base = emm::user_mm_alloc(&mut options).unwrap(); + let mut options = EmaOptions::new(None, ALLOC_SIZE, AllocFlags::COMMIT_NOW); + let base = emm::mm_alloc_user(&mut options).unwrap(); - let res = emm::user_mm_dealloc(base, ALLOC_SIZE); + let res = emm::mm_dealloc(base, ALLOC_SIZE); assert!(res.is_ok()); println!("Successfully run alloc and dealloc!"); SgxStatus::Success diff --git a/sgx_rsrvmm/src/rsrvmm/area.rs b/sgx_rsrvmm/src/rsrvmm/area.rs index 6e2f1588c..95e4d566f 100644 --- a/sgx_rsrvmm/src/rsrvmm/area.rs +++ b/sgx_rsrvmm/src/rsrvmm/area.rs @@ -24,7 +24,7 @@ use core::cmp::{self, Ordering}; use core::convert::From; use core::ops::{Deref, DerefMut}; use core::{fmt, panic}; -use sgx_trts::emm::{rts_mm_modify_perms, ProtFlags}; +use sgx_trts::emm::{mm_modify_perms, ProtFlags}; use sgx_trts::trts; use sgx_types::error::errno::*; use sgx_types::error::OsResult; @@ -367,7 +367,7 @@ impl MmArea { let (pe_needed, pr_needed) = self.is_needed_modify_perm(new_perm)?; if pe_needed || pr_needed { - let res = rts_mm_modify_perms(self.start(), count << SE_PAGE_SHIFT, prot); + let res = mm_modify_perms(self.start(), count << SE_PAGE_SHIFT, prot); if res.is_err() { panic!() } diff --git a/sgx_rsrvmm/src/rsrvmm/mod.rs b/sgx_rsrvmm/src/rsrvmm/mod.rs index f796851d5..821085ab2 100644 --- a/sgx_rsrvmm/src/rsrvmm/mod.rs +++ b/sgx_rsrvmm/src/rsrvmm/mod.rs @@ -161,7 +161,7 @@ impl RsrvMem { ) }; - let ret = emm::rts_mm_commit(start_addr, size >> SE_PAGE_SHIFT); + let ret = emm::mm_commit(start_addr, size >> SE_PAGE_SHIFT); if ret.is_err() { self.committed_size = pre_committed; bail!(ENOMEM); diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs index fea20f020..d9bdde208 100644 --- a/sgx_trts/src/capi.rs +++ b/sgx_trts/src/capi.rs @@ -20,11 +20,11 @@ use crate::call::{ocall, OCallIndex, OcBuffer}; use crate::emm::ema::EmaOptions; use crate::emm::page::AllocFlags; use crate::emm::pfhandler::PfHandler; -use crate::emm::range::{ +use crate::emm::vmmgr::{ ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, PAGE_TYPE_MASK, - PAGE_TYPE_SHIFT, + PAGE_TYPE_SHIFT, RangeType, }; -use crate::emm::{rts_mm_commit, rts_mm_uncommit, user_mm_alloc, PageInfo, PageType, ProtFlags}; +use crate::emm::{mm_commit, mm_uncommit, mm_alloc_user, PageInfo, PageType, ProtFlags, self}; use crate::enclave::{self, is_within_enclave, MmLayout}; use crate::error; use crate::rand::rand; @@ -181,7 +181,19 @@ pub unsafe extern "C" fn sgx_is_outside_enclave(p: *const u8, len: usize) -> i32 #[inline] #[no_mangle] pub unsafe extern "C" fn sgx_commit_rts_pages(addr: usize, count: usize) -> i32 { - if rts_mm_commit(addr, count << SE_PAGE_SHIFT).is_ok() { + let len = count << SE_PAGE_SHIFT; + match emm::check_addr(addr, len) { + Ok(typ) => { + if typ != RangeType::Rts { + return -1; + } + } + Err(_) => { + return -1; + } + } + + if mm_commit(addr, len).is_ok() { 0 } else { -1 @@ -191,7 +203,18 @@ pub unsafe extern "C" fn sgx_commit_rts_pages(addr: usize, count: usize) -> i32 #[inline] #[no_mangle] pub unsafe extern "C" fn sgx_uncommit_rts_pages(addr: usize, count: usize) -> i32 { - if rts_mm_uncommit(addr, count << SE_PAGE_SHIFT).is_ok() { + let len = count << SE_PAGE_SHIFT; + match emm::check_addr(addr, len) { + Ok(typ) => { + if typ != RangeType::Rts { + return -1; + } + } + Err(_) => { + return -1; + } + } + if mm_uncommit(addr, len).is_ok() { 0 } else { -1 @@ -276,7 +299,7 @@ pub unsafe extern "C" fn sgx_mm_alloc( let mut options = EmaOptions::new(addr, size, alloc_flags); options.info(info).handle(handler, priv_data); - match user_mm_alloc(&options) { + match mm_alloc_user(&options) { Ok(base) => { *out_addr = base as *mut u8; 0 diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index d9f39b10f..e3511ff92 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -31,7 +31,7 @@ use spin::{Mutex, Once}; use super::ema::EmaOptions; use super::page::AllocFlags; -use super::range::{RangeType, RM}; +use super::vmmgr::{RangeType, VMMGR}; use super::{PageInfo, PageType, ProtFlags}; use sgx_types::error::OsResult; @@ -465,7 +465,7 @@ impl Reserve { // Here we alloc at least INIT_MEM_SIZE size, // but commit rsize memory, the remaining memory is COMMIT_ON_DEMAND let increment = self.incr_size.max(rsize); - let mut range_manage = RM.get().unwrap().lock(); + let mut vmmgr = VMMGR.get().unwrap().lock(); let mut options = EmaOptions::new(None, increment + 2 * GUARD_SIZE, AllocFlags::RESERVED); @@ -475,7 +475,7 @@ impl Reserve { prot: ProtFlags::NONE, }) .alloc(AllocType::new_static()); - let base = range_manage.alloc(&options, RangeType::User)?; + let base = vmmgr.alloc(&options, RangeType::User)?; let mut options = EmaOptions::new( Some(base + GUARD_SIZE), @@ -484,10 +484,10 @@ impl Reserve { ); options.alloc(AllocType::new_static()); - let base = range_manage.alloc(&options, RangeType::User)?; + let base = vmmgr.alloc(&options, RangeType::User)?; - range_manage.commit(base, rsize, RangeType::User)?; - drop(range_manage); + vmmgr.commit(base, rsize)?; + drop(vmmgr); unsafe { self.write_chunk(base, increment); diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index aa417117a..55cd49fdc 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -32,7 +32,7 @@ use super::pfhandler::PfHandler; /// Enclave Management Area #[repr(C)] -pub struct Ema { +pub(crate) struct Ema { // page aligned start address start: usize, // bytes, round to page bytes @@ -52,7 +52,7 @@ pub struct Ema { } // Implement ema adapter for the operations of intrusive linkedlist -intrusive_adapter!(pub EmaAda = UnsafeRef: Ema { link: LinkedListLink }); +intrusive_adapter!(pub(crate) EmaAda = UnsafeRef: Ema { link: LinkedListLink }); #[derive(Clone, Copy)] /// Options for allocating Emas. @@ -81,28 +81,17 @@ impl Ema { handler: Option, priv_data: Option<*mut c_void>, alloc: AllocType, - ) -> OsResult { - // TODO: check alloc flags' eligibility - - if start != 0 - && length != 0 - && is_within_enclave(start as *const u8, length) - && is_page_aligned!(start) - && (length % crate::arch::SE_PAGE_SIZE) == 0 - { - Ok(Self { - start, - length, - alloc_flags, - info, - eaccept_map: None, - handler, - priv_data, - link: LinkedListLink::new(), - alloc, - }) - } else { - Err(EINVAL) + ) -> Self { + Self { + start, + length, + alloc_flags, + info, + eaccept_map: None, + handler, + priv_data, + link: LinkedListLink::new(), + alloc, } } @@ -152,8 +141,7 @@ impl Ema { self.handler, self.priv_data, AllocType::new_rsrv(), - ) - .unwrap(), + ), allocator, ); ema.start = r_start; @@ -171,8 +159,7 @@ impl Ema { self.handler, self.priv_data, AllocType::new_static(), - ) - .unwrap(), + ), allocator, ); ema.start = r_start; @@ -699,6 +686,23 @@ impl EmaOptions { } } +impl EmaOptions { + pub(crate) fn check(options: &EmaOptions) -> OsResult { + let addr = options.addr.unwrap_or(0); + let size = options.length; + + if addr > 0 { + ensure!( + is_page_aligned!(addr) && is_within_enclave(addr as *const u8, size), + EINVAL + ); + } + ensure!(size != 0 && ((size % SE_PAGE_SIZE) == 0), EINVAL); + + Ok(()) + } +} + impl Ema { pub fn allocate(options: &EmaOptions, apply_now: bool) -> OsResult> { ensure!(options.addr.is_some(), EFAULT); diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs index c6d7e6bfb..0a8618a5d 100644 --- a/sgx_trts/src/emm/init.rs +++ b/sgx_trts/src/emm/init.rs @@ -16,10 +16,10 @@ // under the License.. use super::alloc::{init_reserve_alloc, init_static_alloc}; -use super::range::init_range_manage; +use super::vmmgr::init_vmmgr; pub fn init_emm() { - init_range_manage(); + init_vmmgr(); init_static_alloc(); init_reserve_alloc(); } @@ -39,10 +39,9 @@ mod hw { use crate::emm::ema::EmaOptions; use crate::emm::layout::LayoutTable; use crate::emm::page::AllocFlags; - use crate::emm::range::{mm_init_static_region, EMA_PROT_MASK}; + use crate::emm::vmmgr::{mm_init_static_region, EMA_PROT_MASK}; use crate::emm::{ - rts_mm_alloc, rts_mm_commit, rts_mm_dealloc, rts_mm_modify_perms, PageInfo, PageType, - ProtFlags, + mm_alloc_rts, mm_commit, mm_dealloc, mm_modify_perms, PageInfo, PageType, ProtFlags, }; use crate::enclave::parse; use crate::enclave::MmLayout; @@ -113,7 +112,7 @@ mod hw { }); mm_init_static_region(&options).map_err(|_| SgxStatus::Unexpected)?; - rts_mm_dealloc(addr, size).map_err(|_| SgxStatus::Unexpected)?; + mm_dealloc(addr, size).map_err(|_| SgxStatus::Unexpected)?; } if post_add { @@ -135,7 +134,7 @@ mod hw { | AllocFlags::FIXED, ); - rts_mm_alloc(&options).map_err(|_| SgxStatus::Unexpected)?; + mm_alloc_rts(&options).map_err(|_| SgxStatus::Unexpected)?; } else if static_min { let info = if entry.id == arch::LAYOUT_ID_TCS { PageInfo { @@ -166,7 +165,7 @@ mod hw { .check_dyn_range(addr, count, None) .ok_or(SgxStatus::InvalidParameter)?; - rts_mm_commit(addr, count << arch::SE_PAGE_SHIFT).map_err(|_| SgxStatus::Unexpected)?; + mm_commit(addr, count << arch::SE_PAGE_SHIFT).map_err(|_| SgxStatus::Unexpected)?; Ok(()) } @@ -193,7 +192,7 @@ mod hw { } let prot = ProtFlags::from_bits_truncate(perm as u8); - rts_mm_modify_perms(start, size, prot).map_err(|_| SgxStatus::Unexpected)?; + mm_modify_perms(start, size, prot).map_err(|_| SgxStatus::Unexpected)?; } if typ == Type::GnuRelro { let start = base + trim_to_page!(phdr.virtual_addr() as usize); @@ -202,7 +201,7 @@ mod hw { let size = end - start; if size > 0 { - rts_mm_modify_perms(start, size, ProtFlags::R) + mm_modify_perms(start, size, ProtFlags::R) .map_err(|_| SgxStatus::Unexpected)?; } } @@ -217,7 +216,7 @@ mod hw { let start = base + unsafe { layout.entry.rva as usize }; let size = unsafe { layout.entry.page_count as usize } << arch::SE_PAGE_SHIFT; - rts_mm_modify_perms(start, size, ProtFlags::R).map_err(|_| SgxStatus::Unexpected)?; + mm_modify_perms(start, size, ProtFlags::R).map_err(|_| SgxStatus::Unexpected)?; } Ok(()) } diff --git a/sgx_trts/src/emm/mod.rs b/sgx_trts/src/emm/mod.rs index 44eef03c2..838761fbc 100644 --- a/sgx_trts/src/emm/mod.rs +++ b/sgx_trts/src/emm/mod.rs @@ -25,18 +25,14 @@ pub(crate) mod layout; pub(crate) mod ocall; pub(crate) mod page; pub(crate) mod pfhandler; -pub(crate) mod range; pub(crate) mod tcs; +pub(crate) mod vmmgr; pub use ema::EmaOptions; pub use page::{AllocFlags, PageInfo, PageRange, PageType, ProtFlags}; pub use pfhandler::{PfHandler, PfInfo, Pfec, PfecBits}; -pub use range::{ - rts_mm_alloc, rts_mm_commit, rts_mm_dealloc, rts_mm_modify_perms, rts_mm_modify_type, - rts_mm_uncommit, -}; -pub use range::{ - user_mm_alloc, user_mm_commit, user_mm_dealloc, user_mm_modify_perms, user_mm_modify_type, - user_mm_uncommit, +pub use vmmgr::{ + check_addr, mm_alloc_rts, mm_alloc_user, mm_commit, mm_dealloc, mm_modify_perms, + mm_modify_type, mm_uncommit, }; diff --git a/sgx_trts/src/emm/pfhandler.rs b/sgx_trts/src/emm/pfhandler.rs index 8ca0b2063..62bfd2d72 100644 --- a/sgx_trts/src/emm/pfhandler.rs +++ b/sgx_trts/src/emm/pfhandler.rs @@ -21,7 +21,7 @@ use crate::{ emm::ProtFlags, emm::{ page::AllocFlags, - range::{RangeType, RM}, + vmmgr::{RangeType, VMMGR}, }, veh::HandleResult, }; @@ -97,10 +97,10 @@ pub type PfHandler = extern "C" fn(info: &mut PfInfo, priv_data: *mut c_void) -> pub extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { let addr = trim_to_page!(info.maddr as usize); - let mut range_manage = RM.get().unwrap().lock(); - let mut ema_cursor = match range_manage.search_ema(addr, RangeType::User) { + let mut vmmgr = VMMGR.get().unwrap().lock(); + let mut ema_cursor = match vmmgr.search_ema(addr, RangeType::User) { None => { - let ema_cursor = range_manage.search_ema(addr, RangeType::Rts); + let ema_cursor = vmmgr.search_ema(addr, RangeType::Rts); if ema_cursor.is_none() { return HandleResult::Search; } @@ -112,7 +112,7 @@ pub extern "C" fn mm_enclave_pfhandler(info: &mut PfInfo) -> HandleResult { let ema = unsafe { ema_cursor.get_mut().unwrap() }; let (handler, priv_data) = ema.fault_handler(); if let Some(handler) = handler { - drop(range_manage); + drop(vmmgr); return handler(info, priv_data.unwrap()); } diff --git a/sgx_trts/src/emm/tcs.rs b/sgx_trts/src/emm/tcs.rs index 9675261dd..4165e16b9 100644 --- a/sgx_trts/src/emm/tcs.rs +++ b/sgx_trts/src/emm/tcs.rs @@ -64,7 +64,7 @@ pub fn mktcs(mk_tcs: NonNull) -> SgxResult { mod hw { use crate::arch::{self, Layout, Tcs}; use crate::emm::page::PageType; - use crate::emm::{rts_mm_commit, rts_mm_modify_type}; + use crate::emm::{mm_commit, mm_modify_type}; use crate::enclave::MmLayout; use crate::tcs::list; use core::ptr; @@ -94,7 +94,7 @@ mod hw { if unsafe { layout.entry.attributes & arch::PAGE_ATTR_DYN_THREAD } != 0 { let addr = base + unsafe { layout.entry.rva as usize } + offset; let size = unsafe { layout.entry.page_count } << arch::SE_PAGE_SHIFT; - rts_mm_commit(addr, size as usize).map_err(|_| SgxStatus::Unexpected)?; + mm_commit(addr, size as usize).map_err(|_| SgxStatus::Unexpected)?; } } } @@ -115,7 +115,7 @@ mod hw { tc.ofsbase = tcs_ptr + tc.ofsbase - base as u64; tc.ogsbase = tcs_ptr + tc.ogsbase - base as u64; - rts_mm_modify_type(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE, PageType::Tcs) + mm_modify_type(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE, PageType::Tcs) .map_err(|_| SgxStatus::Unexpected)?; Ok(()) diff --git a/sgx_trts/src/emm/range.rs b/sgx_trts/src/emm/vmmgr.rs similarity index 81% rename from sgx_trts/src/emm/range.rs rename to sgx_trts/src/emm/vmmgr.rs index 757858377..8b24ef40f 100644 --- a/sgx_trts/src/emm/range.rs +++ b/sgx_trts/src/emm/vmmgr.rs @@ -16,7 +16,7 @@ // under the License.. use crate::{ - arch::SE_PAGE_SIZE, + arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}, emm::{PageType, ProtFlags}, enclave::{is_within_enclave, is_within_rts_range, is_within_user_range, MmLayout}, sync::SpinReentrantMutex, @@ -44,80 +44,59 @@ pub const ALLIGNMENT_MASK: usize = 0xFF << ALLIGNMENT_SHIFT; pub const EMA_PROT_MASK: usize = 0x7; -pub(crate) static RM: Once> = Once::new(); +pub(crate) static VMMGR: Once> = Once::new(); /// Initialize range management -pub fn init_range_manage() { - RM.call_once(|| SpinReentrantMutex::new(RangeManage::new())); +pub fn init_vmmgr() { + VMMGR.call_once(|| SpinReentrantMutex::new(VmMgr::new())); } pub fn mm_init_static_region(options: &EmaOptions) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.init_static_region(options) + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.init_static_region(options) } -pub fn user_mm_alloc(options: &EmaOptions) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.alloc(options, RangeType::User) +pub fn mm_alloc_user(options: &EmaOptions) -> OsResult { + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.alloc(options, RangeType::User) } -pub fn user_mm_dealloc(addr: usize, size: usize) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.dealloc(addr, size, RangeType::User) +pub fn mm_alloc_rts(options: &EmaOptions) -> OsResult { + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.alloc(options, RangeType::Rts) } -pub fn user_mm_commit(addr: usize, size: usize) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.commit(addr, size, RangeType::User) +pub fn mm_dealloc(addr: usize, size: usize) -> OsResult { + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.dealloc(addr, size) } -pub fn user_mm_uncommit(addr: usize, size: usize) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.uncommit(addr, size, RangeType::User) +pub fn mm_commit(addr: usize, size: usize) -> OsResult { + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.commit(addr, size) } -pub fn user_mm_modify_type(addr: usize, size: usize, new_page_typ: PageType) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.modify_type(addr, size, new_page_typ, RangeType::User) +pub fn mm_uncommit(addr: usize, size: usize) -> OsResult { + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.uncommit(addr, size) } -pub fn user_mm_modify_perms(addr: usize, size: usize, prot: ProtFlags) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.modify_perms(addr, size, prot, RangeType::User) +pub fn mm_modify_type(addr: usize, size: usize, new_page_typ: PageType) -> OsResult { + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.modify_type(addr, size, new_page_typ) } -pub fn rts_mm_alloc(options: &EmaOptions) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.alloc(options, RangeType::Rts) +pub fn mm_modify_perms(addr: usize, size: usize, prot: ProtFlags) -> OsResult { + let mut vmmgr = VMMGR.get().unwrap().lock(); + vmmgr.modify_perms(addr, size, prot) } -pub fn rts_mm_dealloc(addr: usize, size: usize) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.dealloc(addr, size, RangeType::Rts) +pub fn check_addr(addr: usize, size: usize) -> OsResult { + VmMgr::check(addr, size) } -pub fn rts_mm_commit(addr: usize, size: usize) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.commit(addr, size, RangeType::Rts) -} - -pub fn rts_mm_uncommit(addr: usize, size: usize) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.uncommit(addr, size, RangeType::Rts) -} - -pub fn rts_mm_modify_type(addr: usize, size: usize, new_page_typ: PageType) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.modify_type(addr, size, new_page_typ, RangeType::Rts) -} - -pub fn rts_mm_modify_perms(addr: usize, size: usize, prot: ProtFlags) -> OsResult { - let mut range_manage = RM.get().unwrap().lock(); - range_manage.modify_perms(addr, size, prot, RangeType::Rts) -} - -/// RangeManage manages virtual memory range -pub struct RangeManage { +/// Virtual memory manager +pub(crate) struct VmMgr { user: LinkedList, rts: LinkedList, } @@ -130,7 +109,7 @@ pub enum RangeType { User, } -impl RangeManage { +impl VmMgr { pub fn new() -> Self { Self { user: LinkedList::new(EmaAda::new()), @@ -142,11 +121,7 @@ impl RangeManage { // by the RTS enclave loader at fixed address ranges pub fn init_static_region(&mut self, options: &EmaOptions) -> OsResult { ensure!(options.addr.is_some(), EINVAL); - - // ensure!( - // options.addr != None && size != 0 && is_within_enclave(addr as *const u8, size), - // EINVAL - // ); + EmaOptions::check(options)?; let mut next_ema = self .find_free_region_at(options.addr.unwrap(), options.length, RangeType::Rts) @@ -203,26 +178,12 @@ impl RangeManage { /// Allocate a new memory region in enclave address space (ELRANGE). pub fn alloc(&mut self, options: &EmaOptions, typ: RangeType) -> OsResult { + EmaOptions::check(options)?; + let addr = options.addr.unwrap_or(0); let size = options.length; let end = addr + size; - // Default align is 12 - let align_flag = 12; - let align_mask: usize = (1 << align_flag) - 1; - - if (size % SE_PAGE_SIZE) > 0 { - return Err(EINVAL); - } - - if (addr & align_mask) > 0 { - return Err(EINVAL); - } - - if (addr > 0) && !is_within_enclave(addr as *const u8, size) { - return Err(EINVAL); - } - let mut alloc_addr: Option = None; let mut alloc_next_ema: Option> = None; @@ -256,7 +217,7 @@ impl RangeManage { if alloc_addr.is_none() { let (free_addr, next_ema) = self - .find_free_region(size, 1 << align_flag, typ) + .find_free_region(size, 1 << SE_PAGE_SHIFT, typ) .ok_or(ENOMEM)?; alloc_addr = Some(free_addr); alloc_next_ema = Some(next_ema); @@ -273,7 +234,8 @@ impl RangeManage { /// Commit a partial or full range of memory allocated previously with /// COMMIT_ON_DEMAND. - pub fn commit(&mut self, addr: usize, size: usize, typ: RangeType) -> OsResult { + pub fn commit(&mut self, addr: usize, size: usize) -> OsResult { + let typ = VmMgr::check(addr, size)?; let (mut cursor, ema_num) = self .search_ema_range(addr, addr + size, typ, true) .ok_or(EINVAL)?; @@ -302,7 +264,8 @@ impl RangeManage { } /// Deallocate the address range. - pub fn dealloc(&mut self, addr: usize, size: usize, typ: RangeType) -> OsResult { + pub fn dealloc(&mut self, addr: usize, size: usize) -> OsResult { + let typ = VmMgr::check(addr, size)?; let (mut cursor, mut ema_num) = self .search_ema_range(addr, addr + size, typ, false) .ok_or(EINVAL)?; @@ -326,13 +289,8 @@ impl RangeManage { } /// Change the page type of an allocated region. - pub fn modify_type( - &mut self, - addr: usize, - size: usize, - new_page_typ: PageType, - range_typ: RangeType, - ) -> OsResult { + pub fn modify_type(&mut self, addr: usize, size: usize, new_page_typ: PageType) -> OsResult { + let typ = VmMgr::check(addr, size)?; if new_page_typ != PageType::Tcs { return Err(EPERM); } @@ -342,7 +300,7 @@ impl RangeManage { } let (mut cursor, ema_num) = self - .search_ema_range(addr, addr + size, range_typ, true) + .search_ema_range(addr, addr + size, typ, true) .ok_or(EINVAL)?; assert!(ema_num == 1); unsafe { cursor.get_mut().unwrap().change_to_tcs()? }; @@ -351,17 +309,8 @@ impl RangeManage { } /// Change permissions of an allocated region. - pub fn modify_perms( - &mut self, - addr: usize, - size: usize, - prot: ProtFlags, - typ: RangeType, - ) -> OsResult { - ensure!( - (size != 0) && (size % SE_PAGE_SIZE == 0) && (addr % SE_PAGE_SIZE == 0), - EINVAL - ); + pub fn modify_perms(&mut self, addr: usize, size: usize, prot: ProtFlags) -> OsResult { + let typ = VmMgr::check(addr, size)?; if prot.contains(ProtFlags::X) && !prot.contains(ProtFlags::R) { return Err(EINVAL); @@ -396,7 +345,8 @@ impl RangeManage { } /// Uncommit (trim) physical EPC pages in a previously committed range. - pub fn uncommit(&mut self, addr: usize, size: usize, typ: RangeType) -> OsResult { + pub fn uncommit(&mut self, addr: usize, size: usize) -> OsResult { + let typ = VmMgr::check(addr, size)?; let (mut cursor, ema_num) = self .search_ema_range(addr, addr + size, typ, true) .ok_or(EINVAL)?; @@ -543,22 +493,6 @@ impl RangeManage { len: usize, typ: RangeType, ) -> Option> { - if !is_within_enclave(addr as *const u8, len) { - return None; - } - match typ { - RangeType::Rts => { - if !is_within_rts_range(addr, len) { - return None; - } - } - RangeType::User => { - if !is_within_user_range(addr, len) { - return None; - } - } - } - let mut cursor: CursorMut<'_, EmaAda> = match typ { RangeType::Rts => self.rts.front_mut(), RangeType::User => self.user.front_mut(), @@ -692,3 +626,24 @@ impl RangeManage { None } } + +// Utils +impl VmMgr { + pub fn check(addr: usize, len: usize) -> OsResult { + if addr > 0 { + ensure!( + is_page_aligned!(addr) && is_within_enclave(addr as *const u8, len), + EINVAL + ); + } + ensure!(len != 0 && ((len % SE_PAGE_SIZE) == 0), EINVAL); + + if is_within_rts_range(addr, len) { + Ok(RangeType::Rts) + } else if is_within_user_range(addr, len) { + Ok(RangeType::User) + } else { + Err(EINVAL) + } + } +} diff --git a/sgx_trts/src/enclave/uninit.rs b/sgx_trts/src/enclave/uninit.rs index d59e5931b..04e654f47 100644 --- a/sgx_trts/src/enclave/uninit.rs +++ b/sgx_trts/src/enclave/uninit.rs @@ -16,7 +16,7 @@ // under the License.. use crate::arch; -use crate::emm::rts_mm_dealloc; +use crate::emm::mm_dealloc; use crate::enclave::state::{self, State}; use crate::enclave::{atexit, parse}; use crate::tcs::{list, ThreadControl}; @@ -84,7 +84,7 @@ pub fn rtuninit(tc: ThreadControl) -> SgxResult { if SysFeatures::get().is_edmm() { let mut list_guard = list::TCS_LIST.lock(); for tcs in list_guard.iter_mut().filter(|&t| !ptr::eq(t.as_ptr(), tcs)) { - let result = rts_mm_dealloc(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE); + let result = mm_dealloc(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE); if result.is_err() { state::set_state(State::Crashed); bail!(SgxStatus::Unexpected); From 4ba65925519cba5cd0a94c3b01c4ce918512d4d2 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Thu, 28 Sep 2023 22:57:55 +0800 Subject: [PATCH 16/20] Refine code --- sgx_trts/src/arch.rs | 26 +-- sgx_trts/src/capi.rs | 6 +- sgx_trts/src/emm/alloc.rs | 8 +- sgx_trts/src/emm/bitmap.rs | 49 +++-- sgx_trts/src/emm/ema.rs | 181 ++++++++---------- sgx_trts/src/emm/page.rs | 6 +- sgx_trts/src/emm/vmmgr.rs | 380 ++++++++++++++++++------------------- 7 files changed, 317 insertions(+), 339 deletions(-) diff --git a/sgx_trts/src/arch.rs b/sgx_trts/src/arch.rs index 567136c32..a6ea03de8 100644 --- a/sgx_trts/src/arch.rs +++ b/sgx_trts/src/arch.rs @@ -17,7 +17,7 @@ #![allow(clippy::enum_variant_names)] -use crate::emm::{PageInfo, PageType}; +use crate::emm::{self, PageType}; use crate::tcs::tc; use crate::version::*; use crate::xsave; @@ -744,11 +744,11 @@ impl From for SecInfoFlags { } } -impl From for SecInfoFlags { - fn from(data: edmm::PageInfo) -> SecInfoFlags { +impl From for SecInfoFlags { + fn from(data: emm::PageInfo) -> SecInfoFlags { let typ = data.typ as u64; let prot = data.prot.bits() as u64; - SecinfoFlags::from_bits_truncate((typ << 8) | prot) + SecInfoFlags::from_bits_truncate((typ << 8) | prot) } } @@ -807,33 +807,33 @@ impl From for SecInfo { } } -impl From for SecInfo { - fn from(data: edmm::PageInfo) -> SecInfo { +impl From for SecInfo { + fn from(data: emm::PageInfo) -> SecInfo { SecInfo::from(SecInfoFlags::from(data)) } } #[repr(C, align(32))] #[derive(Clone, Copy, Debug)] -pub struct PageInfo { +pub struct CPageInfo { pub linaddr: u64, pub srcpage: u64, pub secinfo: u64, pub secs: u64, } -impl PageInfo { - pub const ALIGN_SIZE: usize = mem::size_of::(); +impl CPageInfo { + pub const ALIGN_SIZE: usize = mem::size_of::(); } -impl AsRef<[u8; PageInfo::ALIGN_SIZE]> for PageInfo { - fn as_ref(&self) -> &[u8; PageInfo::ALIGN_SIZE] { +impl AsRef<[u8; CPageInfo::ALIGN_SIZE]> for CPageInfo { + fn as_ref(&self) -> &[u8; CPageInfo::ALIGN_SIZE] { unsafe { &*(self as *const _ as *const _) } } } -impl AsRef> for PageInfo { - fn as_ref(&self) -> &Align32<[u8; PageInfo::ALIGN_SIZE]> { +impl AsRef> for CPageInfo { + fn as_ref(&self) -> &Align32<[u8; CPageInfo::ALIGN_SIZE]> { unsafe { &*(self as *const _ as *const _) } } } diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs index d9bdde208..22d5fe314 100644 --- a/sgx_trts/src/capi.rs +++ b/sgx_trts/src/capi.rs @@ -21,10 +21,10 @@ use crate::emm::ema::EmaOptions; use crate::emm::page::AllocFlags; use crate::emm::pfhandler::PfHandler; use crate::emm::vmmgr::{ - ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, PAGE_TYPE_MASK, - PAGE_TYPE_SHIFT, RangeType, + RangeType, ALLIGNMENT_MASK, ALLIGNMENT_SHIFT, ALLOC_FLAGS_MASK, ALLOC_FLAGS_SHIFT, + PAGE_TYPE_MASK, PAGE_TYPE_SHIFT, }; -use crate::emm::{mm_commit, mm_uncommit, mm_alloc_user, PageInfo, PageType, ProtFlags, self}; +use crate::emm::{self, mm_alloc_user, mm_commit, mm_uncommit, PageInfo, PageType, ProtFlags}; use crate::enclave::{self, is_within_enclave, MmLayout}; use crate::error; use crate::rand::rand; diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index e3511ff92..f9368f0f7 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -54,6 +54,8 @@ const SIZE_MASK: usize = !(EXACT_MATCH_INCREMENT - 1); static mut STATIC_MEM: [u8; STATIC_MEM_SIZE] = [0; STATIC_MEM_SIZE]; /// Lowest level: Allocator for static memory +/// +/// TODO: reimplement static allocator with monotone increasing policies static STATIC: Once> = Once::new(); /// Second level: Allocator for reserve memory @@ -228,7 +230,9 @@ impl BlockUsed { intrusive_adapter!(BlockFreeAda = UnsafeRef: BlockFree { link: Link }); -/// Interior allocator for reserve memory management, +/// Interior allocator for reserve memory management +/// +/// TODO: implement slab allocator mechanism pub struct Reserve { exact_blocks: [SinglyLinkedList; 256], large_blocks: SinglyLinkedList, @@ -391,7 +395,7 @@ impl Reserve { return Ok(self.block_to_payload(block)); }; - // AllocType new block from chunks + // Alloc new block from chunks block = self.alloc_from_chunks(bsize); if block.is_none() { let chunk_size = size_of::(); diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index 8b0b41515..0470cc6dc 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -25,6 +25,13 @@ use sgx_types::error::OsResult; use super::alloc::AllocType; +const BYTE_SIZE: usize = 8; +macro_rules! bytes_num { + ($num:expr) => { + ($num + BYTE_SIZE - 1) / BYTE_SIZE + }; +} + #[repr(C)] #[derive(Debug)] pub struct BitArray { @@ -37,7 +44,7 @@ pub struct BitArray { impl BitArray { /// Init BitArray with all zero bits pub fn new(bits: usize, alloc: AllocType) -> OsResult { - let bytes = (bits + 7) / 8; + let bytes = bytes_num!(bits); // FIXME: return error if OOM let data = match alloc { @@ -66,8 +73,8 @@ impl BitArray { return Err(EACCES); } - let byte_index = index / 8; - let bit_index = index % 8; + let byte_index = index / BYTE_SIZE; + let bit_index = index % BYTE_SIZE; let bit_mask = 1 << bit_index; let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; Ok((data.get(byte_index).unwrap() & bit_mask) != 0) @@ -88,8 +95,8 @@ impl BitArray { if index >= self.bits { return Err(EACCES); } - let byte_index = index / 8; - let bit_index = index % 8; + let byte_index = index / BYTE_SIZE; + let bit_index = index % BYTE_SIZE; let bit_mask = 1 << bit_index; let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; @@ -120,33 +127,33 @@ impl BitArray { pub fn split(&mut self, pos: usize) -> OsResult { assert!(pos > 0 && pos < self.bits); - let byte_index = pos / 8; - let bit_index = pos % 8; + let byte_index = pos / BYTE_SIZE; + let bit_index = pos % BYTE_SIZE; - let l_bits = pos; - let l_bytes = (l_bits + 7) / 8; + let lbits = pos; + let lbytes = bytes_num!(lbits); - let r_bits = self.bits - l_bits; - let r_bytes = (r_bits + 7) / 8; + let rbits = self.bits - lbits; + let rbytes = bytes_num!(rbits); - let r_array = Self::new(r_bits, self.alloc)?; + let rarray = Self::new(rbits, self.alloc)?; - let r_data = unsafe { core::slice::from_raw_parts_mut(r_array.data, r_array.bytes) }; - let l_data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; + let rdata = unsafe { core::slice::from_raw_parts_mut(rarray.data, rarray.bytes) }; + let ldata = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; - for (idx, item) in r_data[..(r_bytes - 1)].iter_mut().enumerate() { + for (idx, item) in rdata[..(rbytes - 1)].iter_mut().enumerate() { // current byte index in previous bit_array let curr_idx = idx + byte_index; - let low_bits = l_data[curr_idx] >> bit_index; - let high_bits = l_data[curr_idx + 1] << (8 - bit_index); + let low_bits = ldata[curr_idx] >> bit_index; + let high_bits = ldata[curr_idx + 1] << (8 - bit_index); *item = high_bits | low_bits; } - r_data[r_bytes - 1] = l_data[self.bytes - 1] >> bit_index; + rdata[rbytes - 1] = ldata[self.bytes - 1] >> bit_index; - self.bits = l_bits; - self.bytes = l_bytes; + self.bits = lbits; + self.bytes = lbytes; - Ok(r_array) + Ok(rarray) } } diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index 55cd49fdc..1d2f9bc81 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -31,6 +31,9 @@ use super::page::AllocFlags; use super::pfhandler::PfHandler; /// Enclave Management Area +/// +/// Question: should we replace BitArray with pointer +/// to split struct into two pieces of 80 bytes and 32 bytes or an entity of 104 bytes? #[repr(C)] pub(crate) struct Ema { // page aligned start address @@ -114,14 +117,14 @@ impl Ema { /// Split current ema at specified address, return a new allocated ema /// corresponding to the memory at the range of [addr, end). /// And the current ema manages the memory at the range of [start, addr). - pub fn split(&mut self, addr: usize) -> OsResult<*mut Ema> { - let l_start = self.start; - let l_length = addr - l_start; + pub fn split(&mut self, addr: usize) -> OsResult> { + let laddr = self.start; + let lsize = addr - laddr; - let r_start = addr; - let r_length = (self.start + self.length) - addr; + let raddr = addr; + let rsize = (self.start + self.length) - addr; - let new_bitarray = match &mut self.eaccept_map { + let rarray = match &mut self.eaccept_map { Some(bitarray) => { let pos = (addr - self.start) >> crate::arch::SE_PAGE_SHIFT; Some(bitarray.split(pos)?) @@ -129,10 +132,22 @@ impl Ema { None => None, }; - // Initialize Emawith same allocator - let new_ema: *mut Ema = match self.alloc { + let mut rema = self.clone_ema(); + rema.start = raddr; + rema.length = rsize; + rema.eaccept_map = rarray; + + self.start = laddr; + self.length = lsize; + + Ok(rema) + } + + /// Employ same allocator to Clone Ema without eaccept map + pub(crate) fn clone_ema(&self) -> UnsafeRef { + let ema: *mut Ema = match self.alloc { AllocType::Reserve(allocator) => { - let mut ema = Box::new_in( + let ema = Box::new_in( Ema::new( self.start, self.length, @@ -144,13 +159,10 @@ impl Ema { ), allocator, ); - ema.start = r_start; - ema.length = r_length; - ema.eaccept_map = new_bitarray; Box::into_raw(ema) } AllocType::Static(allocator) => { - let mut ema = Box::new_in( + let ema = Box::new_in( Ema::new( self.start, self.length, @@ -162,39 +174,22 @@ impl Ema { ), allocator, ); - ema.start = r_start; - ema.length = r_length; - ema.eaccept_map = new_bitarray; Box::into_raw(ema) } }; - - self.start = l_start; - self.length = l_length; - - Ok(new_ema) + unsafe { UnsafeRef::from_raw(ema) } } /// Allocate the reserve / committed / virtual memory at corresponding memory pub fn alloc(&mut self) -> OsResult { - // RESERVED region only occupy memory range, but no real allocation + // RESERVED region only occupy memory range with no real allocation if self.alloc_flags.contains(AllocFlags::RESERVED) { return Ok(()); } // Allocate new eaccept_map for COMMIT_ON_DEMAND and COMMIT_NOW if self.eaccept_map.is_none() { - let eaccept_map = match self.alloc { - AllocType::Reserve(_allocator) => { - let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, AllocType::new_rsrv())? - } - AllocType::Static(_allocator) => { - let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, AllocType::new_static())? - } - }; - self.eaccept_map = Some(eaccept_map); + self.init_eaccept_map()?; }; // Ocall to mmap memory in urts @@ -211,7 +206,7 @@ impl Ema { Ok(()) } - /// Eaccept target EPC pages with cpu instruction + /// Eaccept target EPC pages with cpu eaccept instruction fn eaccept(&self, start: usize, length: usize, grow_up: bool) -> OsResult { let info = PageInfo { typ: self.info.typ, @@ -229,23 +224,18 @@ impl Ema { /// Check the prerequisites of ema commitment pub fn commit_check(&self) -> OsResult { - if !self.info.prot.intersects(ProtFlags::RW) { - return Err(EACCES); - } - - if self.info.typ != PageType::Reg { - return Err(EACCES); - } - - if self.alloc_flags.contains(AllocFlags::RESERVED) { - return Err(EACCES); - } + ensure!( + self.info.prot.intersects(ProtFlags::RW) + && self.info.typ == PageType::Reg + && !self.alloc_flags.contains(AllocFlags::RESERVED), + EACCES + ); Ok(()) } /// Commit the corresponding memory of this ema - pub fn commit_self(&mut self) -> OsResult { + pub fn commit_all(&mut self) -> OsResult { self.commit(self.start, self.length) } @@ -284,24 +274,30 @@ impl Ema { /// Check the prerequisites of ema uncommitment pub fn uncommit_check(&self) -> OsResult { - if self.alloc_flags.contains(AllocFlags::RESERVED) { - return Err(EACCES); - } + ensure!(!self.alloc_flags.contains(AllocFlags::RESERVED), EACCES); Ok(()) } /// Uncommit the corresponding memory of this ema - pub fn uncommit_self(&mut self) -> OsResult { + pub fn uncommit_all(&mut self) -> OsResult { + self.uncommit(self.start, self.length) + } + + /// Uncommit the partial memory of this ema + pub fn uncommit(&mut self, start: usize, length: usize) -> OsResult { + // Question: there exists a problem: + // If developers trim partial pages of the ema with none protection flag, + // the protection flag of left committed pages would be modified to Read implicitly. let prot = self.info.prot; if prot == ProtFlags::NONE && (self.info.typ != PageType::Tcs) { self.modify_perm(ProtFlags::R)? } - self.uncommit(self.start, self.length, prot) + self.uncommit_inner(start, length, prot) } - /// Uncommit the partial memory of this ema - pub fn uncommit(&mut self, start: usize, length: usize, prot: ProtFlags) -> OsResult { + #[inline] + fn uncommit_inner(&mut self, start: usize, length: usize, prot: ProtFlags) -> OsResult { assert!(self.eaccept_map.is_some()); if self.alloc_flags.contains(AllocFlags::RESERVED) { @@ -389,13 +385,10 @@ impl Ema { /// Check the prerequisites of modifying permissions pub fn modify_perm_check(&self) -> OsResult { - if self.info.typ != PageType::Reg { - return Err(EACCES); - } - - if self.alloc_flags.contains(AllocFlags::RESERVED) { - return Err(EACCES); - } + ensure!( + (self.info.typ == PageType::Reg && !self.alloc_flags.contains(AllocFlags::RESERVED)), + EACCES + ); match &self.eaccept_map { Some(bitmap) => { @@ -473,23 +466,19 @@ impl Ema { /// Changing the page type from Reg to Tcs pub fn change_to_tcs(&mut self) -> OsResult { // The ema must have and only have one page - if self.length != SE_PAGE_SIZE { - return Err(EINVAL); - } - // The page must be committed - if !self.is_page_committed(self.start) { - return Err(EACCES); - } + ensure!(self.length == SE_PAGE_SIZE, EINVAL); + ensure!(self.is_page_committed(self.start), EACCES); let info = self.info; if info.typ == PageType::Tcs { return Ok(()); } - if (info.prot != ProtFlags::RW) || (info.typ != PageType::Reg) { - return Err(EACCES); - } + ensure!( + (info.prot == ProtFlags::RW) && (info.typ == PageType::Reg), + EACCES + ); ocall::modify_ocall( self.start, @@ -541,7 +530,7 @@ impl Ema { if self.info.prot == ProtFlags::NONE && (self.info.typ != PageType::Tcs) { self.modify_perm(ProtFlags::R)?; } - self.uncommit(self.start, self.length, ProtFlags::NONE)?; + self.uncommit_inner(self.start, self.length, ProtFlags::NONE)?; Ok(()) } @@ -583,24 +572,29 @@ impl Ema { pub fn set_eaccept_map_full(&mut self) -> OsResult { if self.eaccept_map.is_none() { - let mut eaccept_map = match self.alloc { - AllocType::Reserve(_allocator) => { - let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, AllocType::new_rsrv())? - } - AllocType::Static(_allocator) => { - let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, AllocType::new_static())? - } - }; - eaccept_map.set_full(); - self.eaccept_map = Some(eaccept_map); + self.init_eaccept_map()?; + self.eaccept_map.as_mut().unwrap().set_full(); } else { self.eaccept_map.as_mut().unwrap().set_full(); } Ok(()) } + fn init_eaccept_map(&mut self) -> OsResult { + let eaccept_map = match self.alloc { + AllocType::Reserve(_allocator) => { + let page_num = self.length >> SE_PAGE_SHIFT; + BitArray::new(page_num, AllocType::new_rsrv())? + } + AllocType::Static(_allocator) => { + let page_num = self.length >> SE_PAGE_SHIFT; + BitArray::new(page_num, AllocType::new_static())? + } + }; + self.eaccept_map = Some(eaccept_map); + Ok(()) + } + fn set_flags(&mut self, flags: AllocFlags) { self.alloc_flags = flags; } @@ -723,24 +717,3 @@ impl Ema { Ok(new_ema) } } - -// pub struct EmaRange<'a> { -// pub cursor: CursorMut<'a, EmaAda>, -// pub count : usize, -// } - -// impl<'a> Iterator for EmaRange<'a> { -// type Item = &'a mut EMA; - -// fn next(&mut self) -> Option { -// if self.count == 0 { -// None -// } else { -// self.cursor.move_next(); -// self.count -= 1; - -// let ema = unsafe { self.cursor.get_mut().unwrap() }; -// Some(ema) -// } -// } -// } diff --git a/sgx_trts/src/emm/page.rs b/sgx_trts/src/emm/page.rs index 1dafcd75f..be5ca13b6 100644 --- a/sgx_trts/src/emm/page.rs +++ b/sgx_trts/src/emm/page.rs @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License.. -use crate::arch::{Secinfo, SE_PAGE_SHIFT, SE_PAGE_SIZE}; +use crate::arch::{SecInfo, SE_PAGE_SHIFT, SE_PAGE_SIZE}; use crate::enclave::is_within_enclave; use crate::inst::EncluInst; use bitflags::bitflags; @@ -228,12 +228,12 @@ impl Page { } pub fn accept(&self) -> OsResult { - let secinfo: Secinfo = self.info.into(); + let secinfo: SecInfo = self.info.into(); EncluInst::eaccept(&secinfo, self.addr).map_err(|_| EFAULT) } pub fn modpe(&self) -> OsResult { - let secinfo: Secinfo = self.info.into(); + let secinfo: SecInfo = self.info.into(); EncluInst::emodpe(&secinfo, self.addr).map_err(|_| EFAULT) } } diff --git a/sgx_trts/src/emm/vmmgr.rs b/sgx_trts/src/emm/vmmgr.rs index 8b24ef40f..7722ac127 100644 --- a/sgx_trts/src/emm/vmmgr.rs +++ b/sgx_trts/src/emm/vmmgr.rs @@ -22,7 +22,10 @@ use crate::{ sync::SpinReentrantMutex, }; use alloc::boxed::Box; -use intrusive_collections::{linked_list::CursorMut, LinkedList, UnsafeRef}; +use intrusive_collections::{ + linked_list::{Cursor, CursorMut}, + LinkedList, UnsafeRef, +}; use sgx_tlibc_sys::{EEXIST, EINVAL, ENOMEM, EPERM}; use sgx_types::error::OsResult; use spin::Once; @@ -128,69 +131,30 @@ impl VmMgr { .ok_or(EINVAL)?; let mut new_ema = Ema::allocate(options, false)?; - if !options.alloc_flags.contains(AllocFlags::RESERVED) { new_ema.set_eaccept_map_full()?; } - next_ema.insert_before(new_ema); Ok(()) } - // Clear the Emas in charging of [start, end) memory region, - // return next ema cursor - fn clear_reserved_emas( - &mut self, - start: usize, - end: usize, - typ: RangeType, - alloc: AllocType, - ) -> Option> { - let (mut cursor, ema_num) = self.search_ema_range(start, end, typ, true)?; - let start_ema_ptr = cursor.get().unwrap() as *const Ema; - - // Check Emaattributes - let mut count = ema_num; - while count != 0 { - let ema = cursor.get().unwrap(); - // Emamust be reserved and can not manage internal memory region - if !ema.flags().contains(AllocFlags::RESERVED) || ema.allocator() != alloc { - return None; - } - cursor.move_next(); - count -= 1; - } - - let mut cursor = match typ { - RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, - RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, - }; - - count = ema_num; - while count != 0 { - cursor.remove(); - count -= 1; - } - - Some(cursor) - } - /// Allocate a new memory region in enclave address space (ELRANGE). pub fn alloc(&mut self, options: &EmaOptions, typ: RangeType) -> OsResult { EmaOptions::check(options)?; - let addr = options.addr.unwrap_or(0); + // let addr = options.addr.unwrap_or(0); + let addr = options.addr; let size = options.length; - let end = addr + size; + // let end = addr + size; let mut alloc_addr: Option = None; let mut alloc_next_ema: Option> = None; - if addr > 0 { + if let Some(addr) = addr { + let end = addr + options.length; let is_fixed_alloc = options.alloc_flags.contains(AllocFlags::FIXED); - // FIXME: search_ema_range implicitly contains splitting ema - let range = self.search_ema_range(addr, end, typ, false); + let range = self.search_ema_range(addr, end, typ, false, false); match range { // exist in emas list @@ -232,33 +196,64 @@ impl VmMgr { Ok(alloc_addr.unwrap()) } + /// Change permissions of an allocated region. + pub fn modify_perms(&mut self, addr: usize, size: usize, prot: ProtFlags) -> OsResult { + if prot.contains(ProtFlags::X) && !prot.contains(ProtFlags::R) { + return Err(EINVAL); + } + self.apply_commands( + addr, + size, + true, + |cursor| cursor.get().unwrap().modify_perm_check(), + |cursor| unsafe { cursor.get_mut().unwrap().modify_perm(prot) }, + )?; + + Ok(()) + } + /// Commit a partial or full range of memory allocated previously with /// COMMIT_ON_DEMAND. + /// + /// TODO: don't split Emas when committing pages pub fn commit(&mut self, addr: usize, size: usize) -> OsResult { - let typ = VmMgr::check(addr, size)?; - let (mut cursor, ema_num) = self - .search_ema_range(addr, addr + size, typ, true) - .ok_or(EINVAL)?; - let start_ema_ptr = cursor.get().unwrap() as *const Ema; - - let mut count = ema_num; - while count != 0 { - cursor.get().unwrap().commit_check()?; - cursor.move_next(); - count -= 1; - } + let end = addr + size; + self.apply_commands( + addr, + size, + false, + |cursor| cursor.get().unwrap().commit_check(), + |cursor| { + let ema = unsafe { cursor.get_mut().unwrap() }; + let start = addr.max(ema.start()); + let end = end.min(ema.end()); + ema.commit(start, end - start) + }, + )?; - let mut cursor = match typ { - RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, - RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, - }; + Ok(()) + } - count = ema_num; - while count != 0 { - unsafe { cursor.get_mut().unwrap().commit_self()? }; - cursor.move_next(); - count -= 1; - } + /// Uncommit (trim) physical EPC pages in a previously committed range. + /// + /// TODO: don't split Emas when trimming pages + /// + /// Question: There exist commit_now Emas with no pages if trimming, + /// How should we treat those null commit_now Emas? + pub fn uncommit(&mut self, addr: usize, size: usize) -> OsResult { + let end = addr + size; + self.apply_commands( + addr, + size, + false, + |cursor| cursor.get().unwrap().uncommit_check(), + |cursor| { + let ema = unsafe { cursor.get_mut().unwrap() }; + let start = addr.max(ema.start()); + let end = end.min(ema.end()); + ema.uncommit(start, end - start) + }, + )?; Ok(()) } @@ -267,14 +262,14 @@ impl VmMgr { pub fn dealloc(&mut self, addr: usize, size: usize) -> OsResult { let typ = VmMgr::check(addr, size)?; let (mut cursor, mut ema_num) = self - .search_ema_range(addr, addr + size, typ, false) + .search_ema_range(addr, addr + size, typ, false, true) .ok_or(EINVAL)?; while ema_num != 0 { // Calling remove() implicitly moves cursor pointing to next ema let mut ema = cursor.remove().unwrap(); ema.dealloc()?; - // Drop inner Ema + // Drop inner Ema inexplicitly match ema.allocator() { AllocType::Reserve(allocator) => { let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), allocator) }; @@ -291,105 +286,63 @@ impl VmMgr { /// Change the page type of an allocated region. pub fn modify_type(&mut self, addr: usize, size: usize, new_page_typ: PageType) -> OsResult { let typ = VmMgr::check(addr, size)?; - if new_page_typ != PageType::Tcs { - return Err(EPERM); - } - - if size != SE_PAGE_SIZE { - return Err(EINVAL); - } + ensure!(new_page_typ == PageType::Tcs, EPERM); + ensure!(size == SE_PAGE_SIZE, EINVAL); let (mut cursor, ema_num) = self - .search_ema_range(addr, addr + size, typ, true) + .search_ema_range(addr, addr + size, typ, true, true) .ok_or(EINVAL)?; - assert!(ema_num == 1); + debug_assert!(ema_num == 1); unsafe { cursor.get_mut().unwrap().change_to_tcs()? }; Ok(()) } - /// Change permissions of an allocated region. - pub fn modify_perms(&mut self, addr: usize, size: usize, prot: ProtFlags) -> OsResult { - let typ = VmMgr::check(addr, size)?; - - if prot.contains(ProtFlags::X) && !prot.contains(ProtFlags::R) { - return Err(EINVAL); - } - - let (mut cursor, ema_num) = self - .search_ema_range(addr, addr + size, typ, true) - .ok_or(EINVAL)?; + // Clear the reserved Emas in charging of [start, end) memory region, + // return next ema cursor + #[inline] + fn clear_reserved_emas( + &mut self, + start: usize, + end: usize, + typ: RangeType, + alloc: AllocType, + ) -> Option> { + let (mut cursor, ema_num) = self.search_ema_range(start, end, typ, true, true)?; let start_ema_ptr = cursor.get().unwrap() as *const Ema; - let mut count = ema_num; while count != 0 { let ema = cursor.get().unwrap(); - ema.modify_perm_check()?; - cursor.move_next(); - count -= 1; - } - - let mut cursor = match typ { - RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, - RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, - }; - - count = ema_num; - while count != 0 { - unsafe { cursor.get_mut().unwrap().modify_perm(prot)? }; - cursor.move_next(); - count -= 1; - } - - Ok(()) - } - - /// Uncommit (trim) physical EPC pages in a previously committed range. - pub fn uncommit(&mut self, addr: usize, size: usize) -> OsResult { - let typ = VmMgr::check(addr, size)?; - let (mut cursor, ema_num) = self - .search_ema_range(addr, addr + size, typ, true) - .ok_or(EINVAL)?; - let start_ema_ptr = cursor.get().unwrap() as *const Ema; - - let mut count = ema_num; - while count != 0 { - cursor.get().unwrap().uncommit_check()?; + // Ema must be reserved and can not manage internal memory region + if !ema.flags().contains(AllocFlags::RESERVED) || ema.allocator() != alloc { + return None; + } cursor.move_next(); count -= 1; } - let mut cursor = match typ { - RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, - RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, - }; - + let mut cursor = unsafe { self.cursor_mut_from_ptr(start_ema_ptr, typ) }; count = ema_num; while count != 0 { - unsafe { cursor.get_mut().unwrap().uncommit_self()? }; - cursor.move_next(); + cursor.remove(); count -= 1; } - Ok(()) + Some(cursor) } - // search for a range of nodes containing addresses within [start, end) - // 'ema_begin' will hold the fist ema that has address higher than /euqal to - // 'start' 'ema_end' will hold the node immediately follow the last ema that has - // address lower than / equal to 'end' - // return ema_end and ema num + /// Search for a range of Emas containing addresses within [start, end). + /// + /// Return the mutable cursor of start ema and ema number. fn search_ema_range( &mut self, start: usize, end: usize, typ: RangeType, continuous: bool, + split: bool, ) -> Option<(CursorMut<'_, EmaAda>, usize)> { - let mut cursor = match typ { - RangeType::Rts => self.rts.front(), - RangeType::User => self.user.front(), - }; + let mut cursor = self.front(typ); while !cursor.is_null() && cursor.get().unwrap().lower_than_addr(start) { cursor.move_next(); @@ -400,7 +353,6 @@ impl VmMgr { } let mut curr_ema = cursor.get().unwrap(); - let mut start_ema_ptr = curr_ema as *const Ema; let mut emas_num = 0; let mut prev_end = curr_ema.start(); @@ -418,60 +370,49 @@ impl VmMgr { cursor.move_next(); } - let mut end_ema_ptr = curr_ema as *const Ema; - - // Spliting start ema - let mut start_cursor = match typ { - RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, - RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, - }; - - let curr_ema = unsafe { start_cursor.get_mut().unwrap() }; - let ema_start = curr_ema.start(); - - // Problem may exist, need to check!! - if ema_start < start { - let right_ema = curr_ema.split(start).unwrap() as *const Ema; - let right_ema_ref = unsafe { UnsafeRef::from_raw(right_ema) }; - start_cursor.insert_after(right_ema_ref); - start_cursor.move_next(); - start_ema_ptr = start_cursor.get().unwrap() as *const Ema; - } + // Spliting end ema + if split { + let mut end_ema_ptr = curr_ema as *const Ema; + // Spliting start ema + let mut start_cursor = unsafe { self.cursor_mut_from_ptr(start_ema_ptr, typ) }; + + let curr_ema = unsafe { start_cursor.get_mut().unwrap() }; + let ema_start = curr_ema.start(); + + if ema_start < start { + let right_ema = curr_ema.split(start).unwrap(); + start_cursor.insert_after(right_ema); + // start cursor moves next to refer real start ema + start_cursor.move_next(); + // ptr points to the address of real start ema + start_ema_ptr = start_cursor.get().unwrap() as *const Ema; + } - if emas_num == 1 { - end_ema_ptr = start_ema_ptr; - } + // Spliting end ema + if emas_num == 1 { + end_ema_ptr = start_ema_ptr; + } - // Spliting end ema - let mut end_cursor = match typ { - RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(end_ema_ptr) }, - RangeType::User => unsafe { self.user.cursor_mut_from_ptr(end_ema_ptr) }, - }; + let mut end_cursor = unsafe { self.cursor_mut_from_ptr(end_ema_ptr, typ) }; - let end_ema = unsafe { end_cursor.get_mut().unwrap() }; - let ema_end = end_ema.end(); + let end_ema = unsafe { end_cursor.get_mut().unwrap() }; + let ema_end = end_ema.end(); - if ema_end > end { - let right_ema = end_ema.split(end).unwrap(); - let right_ema_ref = unsafe { UnsafeRef::from_raw(right_ema) }; - end_cursor.insert_after(right_ema_ref); + if ema_end > end { + let right_ema = end_ema.split(end).unwrap(); + end_cursor.insert_after(right_ema); + } } // Recover start ema and return it as range - let start_cursor = match typ { - RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(start_ema_ptr) }, - RangeType::User => unsafe { self.user.cursor_mut_from_ptr(start_ema_ptr) }, - }; + let start_cursor = unsafe { self.cursor_mut_from_ptr(start_ema_ptr, typ) }; Some((start_cursor, emas_num)) } - // search for a ema node whose memory range contains address + // Search for a ema node whose memory range contains address pub fn search_ema(&mut self, addr: usize, typ: RangeType) -> Option> { - let mut cursor = match typ { - RangeType::Rts => self.rts.front_mut(), - RangeType::User => self.user.front_mut(), - }; + let mut cursor = self.front_mut(typ); while !cursor.is_null() { let ema = cursor.get().unwrap(); @@ -493,10 +434,7 @@ impl VmMgr { len: usize, typ: RangeType, ) -> Option> { - let mut cursor: CursorMut<'_, EmaAda> = match typ { - RangeType::Rts => self.rts.front_mut(), - RangeType::User => self.user.front_mut(), - }; + let mut cursor = self.front_mut(typ); while !cursor.is_null() { let start_curr = cursor.get().map(|ema| ema.start()).unwrap(); @@ -512,7 +450,7 @@ impl VmMgr { } } - // means addr is larger than the end of the last ema node + // Means addr is larger than the end of the last ema node if cursor.is_null() { return Some(cursor); } @@ -530,13 +468,8 @@ impl VmMgr { ) -> Option<(usize, CursorMut<'_, EmaAda>)> { let user_base = MmLayout::user_region_mem_base(); let user_end = user_base + MmLayout::user_region_mem_size(); - let mut addr; - - let mut cursor: CursorMut<'_, EmaAda> = match typ { - RangeType::Rts => self.rts.front_mut(), - RangeType::User => self.user.front_mut(), - }; + let mut cursor = self.front_mut(typ); // no ema in list if cursor.is_null() { @@ -625,6 +558,67 @@ impl VmMgr { None } + + fn front_mut(&mut self, typ: RangeType) -> CursorMut<'_, EmaAda> { + match typ { + RangeType::Rts => self.rts.front_mut(), + RangeType::User => self.user.front_mut(), + } + } + + fn front(&self, typ: RangeType) -> Cursor<'_, EmaAda> { + match typ { + RangeType::Rts => self.rts.front(), + RangeType::User => self.user.front(), + } + } + + unsafe fn cursor_mut_from_ptr( + &mut self, + ptr: *const Ema, + typ: RangeType, + ) -> CursorMut<'_, EmaAda> { + match typ { + RangeType::Rts => unsafe { self.rts.cursor_mut_from_ptr(ptr) }, + RangeType::User => unsafe { self.user.cursor_mut_from_ptr(ptr) }, + } + } + + fn apply_commands( + &mut self, + addr: usize, + size: usize, + split: bool, + check: F1, + commands: F2, + ) -> OsResult + where + F1: Fn(&CursorMut<'_, EmaAda>) -> OsResult, + F2: Fn(&mut CursorMut<'_, EmaAda>) -> OsResult, + { + let typ = VmMgr::check(addr, size)?; + let (mut cursor, ema_num) = self + .search_ema_range(addr, addr + size, typ, true, split) + .ok_or(EINVAL)?; + let start_ema_ptr = cursor.get().unwrap() as *const Ema; + + let mut count = ema_num; + while count != 0 { + check(&cursor)?; + cursor.move_next(); + count -= 1; + } + + let mut cursor = unsafe { self.cursor_mut_from_ptr(start_ema_ptr, typ) }; + count = ema_num; + while count != 0 { + commands(&mut cursor)?; + cursor.move_next(); + count -= 1; + } + + Ok(()) + } } // Utils From 47b39963a031ae3850a6a9d51b651ee89b4b8d91 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Thu, 30 Nov 2023 20:29:14 +0800 Subject: [PATCH 17/20] refine code --- sgx_trts/src/emm/alloc.rs | 43 ++++++++++---- sgx_trts/src/emm/bitmap.rs | 89 +++++++++------------------- sgx_trts/src/emm/ema.rs | 105 ++++++++------------------------- sgx_trts/src/emm/init.rs | 57 ++++++++---------- sgx_trts/src/emm/page.rs | 4 +- sgx_trts/src/emm/tcs.rs | 17 ++++++ sgx_trts/src/emm/vmmgr.rs | 13 ++-- sgx_trts/src/enclave/mem.rs | 6 ++ sgx_trts/src/enclave/uninit.rs | 16 +---- sgx_trts/src/lib.rs | 2 + 10 files changed, 138 insertions(+), 214 deletions(-) diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index f9368f0f7..d8e679381 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -22,12 +22,13 @@ use intrusive_collections::singly_linked_list::{Link, SinglyLinkedList}; use intrusive_collections::UnsafeRef; use sgx_tlibc_sys::ENOMEM; +use crate::sync::SpinMutex as Mutex; use core::alloc::{AllocError, Allocator, Layout}; +use core::any::Any; use core::mem::size_of; -use core::mem::transmute; use core::mem::MaybeUninit; use core::ptr::NonNull; -use spin::{Mutex, Once}; +use spin::Once; use super::ema::EmaOptions; use super::page::AllocFlags; @@ -80,6 +81,10 @@ pub fn init_reserve_alloc() { RSRV_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); } +pub trait EmmAllocator: Allocator + Any { + fn as_any(&self) -> &dyn Any; +} + /// AllocType layout memory from reserve memory region #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RsrvAlloc; @@ -102,6 +107,12 @@ unsafe impl Allocator for RsrvAlloc { } } +impl EmmAllocator for RsrvAlloc { + fn as_any(&self) -> &dyn Any { + self + } +} + /// AllocType layout memory from static memory region #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct StaticAlloc; @@ -123,23 +134,29 @@ unsafe impl Allocator for StaticAlloc { } } +impl EmmAllocator for StaticAlloc { + fn as_any(&self) -> &dyn Any { + self + } +} + // Enum for allocator types #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum AllocType { - Static(StaticAlloc), - Reserve(RsrvAlloc), + Static, + Reserve, } impl AllocType { - pub fn new_static() -> Self { - Self::Static(StaticAlloc) - } - - pub fn new_rsrv() -> Self { - Self::Reserve(RsrvAlloc) + pub fn alloctor(&self) -> &'static dyn EmmAllocator { + match self { + AllocType::Static => &StaticAlloc, + AllocType::Reserve => &RsrvAlloc, + } } } + // Chunk manages memory range. // The Chunk structure is filled into the layout before the base pointer. #[derive(Debug)] @@ -252,7 +269,7 @@ impl Reserve { for block in &mut exact_blocks { block.write(SinglyLinkedList::new(BlockFreeAda::new())); } - unsafe { transmute(exact_blocks) } + unsafe { MaybeUninit::array_assume_init(exact_blocks) } }; let mut reserve = Self { @@ -478,7 +495,7 @@ impl Reserve { typ: PageType::None, prot: ProtFlags::NONE, }) - .alloc(AllocType::new_static()); + .alloc(AllocType::Static); let base = vmmgr.alloc(&options, RangeType::User)?; let mut options = EmaOptions::new( @@ -487,7 +504,7 @@ impl Reserve { AllocFlags::COMMIT_ON_DEMAND | AllocFlags::FIXED, ); - options.alloc(AllocType::new_static()); + options.alloc(AllocType::Static); let base = vmmgr.alloc(&options, RangeType::User)?; vmmgr.commit(base, rsize)?; diff --git a/sgx_trts/src/emm/bitmap.rs b/sgx_trts/src/emm/bitmap.rs index 0470cc6dc..ed302f5df 100644 --- a/sgx_trts/src/emm/bitmap.rs +++ b/sgx_trts/src/emm/bitmap.rs @@ -17,12 +17,13 @@ use alloc::boxed::Box; use alloc::vec; -use core::alloc::Allocator; -use core::alloc::Layout; -use core::ptr::NonNull; use sgx_tlibc_sys::EACCES; use sgx_types::error::OsResult; +use crate::emm::alloc::EmmAllocator; +use crate::emm::alloc::RsrvAlloc; +use crate::emm::alloc::StaticAlloc; + use super::alloc::AllocType; const BYTE_SIZE: usize = 8; @@ -32,13 +33,11 @@ macro_rules! bytes_num { }; } -#[repr(C)] #[derive(Debug)] pub struct BitArray { bits: usize, bytes: usize, - data: *mut u8, - alloc: AllocType, + data: Box<[u8], &'static dyn EmmAllocator>, } impl BitArray { @@ -47,24 +46,9 @@ impl BitArray { let bytes = bytes_num!(bits); // FIXME: return error if OOM - let data = match alloc { - AllocType::Reserve(allocator) => { - // Set bits to all zeros - let data = vec::from_elem_in(0_u8, bytes, allocator).into_boxed_slice(); - Box::into_raw(data) as *mut u8 - } - AllocType::Static(allocator) => { - let data = vec::from_elem_in(0_u8, bytes, allocator).into_boxed_slice(); - Box::into_raw(data) as *mut u8 - } - }; - - Ok(Self { - bits, - bytes, - data, - alloc, - }) + let data = vec::from_elem_in(0_u8, bytes, alloc.alloctor()).into_boxed_slice(); + + Ok(Self { bits, bytes, data }) } /// Get the value of the bit at a given index @@ -76,8 +60,7 @@ impl BitArray { let byte_index = index / BYTE_SIZE; let bit_index = index % BYTE_SIZE; let bit_mask = 1 << bit_index; - let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; - Ok((data.get(byte_index).unwrap() & bit_mask) != 0) + Ok((self.data.get(byte_index).unwrap() & bit_mask) != 0) } /// Check whether all bits are set true @@ -99,26 +82,33 @@ impl BitArray { let bit_index = index % BYTE_SIZE; let bit_mask = 1 << bit_index; - let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; - if value { - data[byte_index] |= bit_mask; + self.data[byte_index] |= bit_mask; } else { - data[byte_index] &= !bit_mask; + self.data[byte_index] &= !bit_mask; } Ok(()) } /// Set all the bits to true pub fn set_full(&mut self) { - let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; - data.fill(0xFF); + self.data.fill(0xFF); } /// Clear all the bits pub fn clear(&mut self) { - let data = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; - data.fill(0); + self.data.fill(0); + } + + fn alloc_type(&self) -> AllocType { + let allocator = *Box::allocator(&self.data); + if allocator.as_any().downcast_ref::().is_some() { + AllocType::Reserve + } else if allocator.as_any().downcast_ref::().is_some() { + AllocType::Static + } else { + panic!() + } } /// Split current bit array at specified position, return a new allocated bit array @@ -136,11 +126,10 @@ impl BitArray { let rbits = self.bits - lbits; let rbytes = bytes_num!(rbits); - let rarray = Self::new(rbits, self.alloc)?; - - let rdata = unsafe { core::slice::from_raw_parts_mut(rarray.data, rarray.bytes) }; - let ldata = unsafe { core::slice::from_raw_parts_mut(self.data, self.bytes) }; + let mut rarray = Self::new(rbits, self.alloc_type())?; + let rdata = &mut rarray.data; + let ldata = &mut self.data; for (idx, item) in rdata[..(rbytes - 1)].iter_mut().enumerate() { // current byte index in previous bit_array let curr_idx = idx + byte_index; @@ -156,27 +145,3 @@ impl BitArray { Ok(rarray) } } - -impl Drop for BitArray { - fn drop(&mut self) { - match self.alloc { - AllocType::Reserve(allocator) => { - // Layout is redundant since interior allocator maintains the allocated size. - // Besides, if the bitmap is splitted, the recorded size - // in bitmap is not corresponding to allocated layout. - let fake_layout: Layout = Layout::new::(); - unsafe { - let data_ptr = NonNull::new_unchecked(self.data); - allocator.deallocate(data_ptr, fake_layout); - } - } - AllocType::Static(allocator) => { - let fake_layout: Layout = Layout::new::(); - unsafe { - let data_ptr = NonNull::new_unchecked(self.data); - allocator.deallocate(data_ptr, fake_layout); - } - } - } - } -} diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index 1d2f9bc81..bb36be17b 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -19,12 +19,12 @@ use crate::arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}; use crate::emm::{PageInfo, PageRange, PageType, ProtFlags}; use crate::enclave::is_within_enclave; use alloc::boxed::Box; +use core::alloc::Allocator; use intrusive_collections::{intrusive_adapter, LinkedListLink, UnsafeRef}; use sgx_tlibc_sys::{c_void, EACCES, EFAULT, EINVAL}; use sgx_types::error::OsResult; use super::alloc::AllocType; -use super::alloc::{RsrvAlloc, StaticAlloc}; use super::bitmap::BitArray; use super::ocall; use super::page::AllocFlags; @@ -34,7 +34,6 @@ use super::pfhandler::PfHandler; /// /// Question: should we replace BitArray with pointer /// to split struct into two pieces of 80 bytes and 32 bytes or an entity of 104 bytes? -#[repr(C)] pub(crate) struct Ema { // page aligned start address start: usize, @@ -76,29 +75,7 @@ unsafe impl Sync for Ema {} impl Ema { /// Initialize Emanode with null eaccept map, /// and start address must be page aligned - pub fn new( - start: usize, - length: usize, - alloc_flags: AllocFlags, - info: PageInfo, - handler: Option, - priv_data: Option<*mut c_void>, - alloc: AllocType, - ) -> Self { - Self { - start, - length, - alloc_flags, - info, - eaccept_map: None, - handler, - priv_data, - link: LinkedListLink::new(), - alloc, - } - } - - pub fn new_options(options: &EmaOptions) -> OsResult { + pub fn new(options: &EmaOptions) -> OsResult { ensure!(options.addr.is_some(), EINVAL); Ok(Self { @@ -145,39 +122,15 @@ impl Ema { /// Employ same allocator to Clone Ema without eaccept map pub(crate) fn clone_ema(&self) -> UnsafeRef { - let ema: *mut Ema = match self.alloc { - AllocType::Reserve(allocator) => { - let ema = Box::new_in( - Ema::new( - self.start, - self.length, - self.alloc_flags, - self.info, - self.handler, - self.priv_data, - AllocType::new_rsrv(), - ), - allocator, - ); - Box::into_raw(ema) - } - AllocType::Static(allocator) => { - let ema = Box::new_in( - Ema::new( - self.start, - self.length, - self.alloc_flags, - self.info, - self.handler, - self.priv_data, - AllocType::new_static(), - ), - allocator, - ); - Box::into_raw(ema) - } - }; - unsafe { UnsafeRef::from_raw(ema) } + let mut ema_options = EmaOptions::new(Some(self.start), self.length, self.alloc_flags); + ema_options + .info(self.info) + .handle(self.handler, self.priv_data) + .alloc(self.alloc); + + let allocator = self.alloc.alloctor(); + let ema = Box::new_in(Ema::new(&ema_options).unwrap(), allocator); + unsafe { UnsafeRef::from_raw(Box::into_raw(ema)) } } /// Allocate the reserve / committed / virtual memory at corresponding memory @@ -581,16 +534,8 @@ impl Ema { } fn init_eaccept_map(&mut self) -> OsResult { - let eaccept_map = match self.alloc { - AllocType::Reserve(_allocator) => { - let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, AllocType::new_rsrv())? - } - AllocType::Static(_allocator) => { - let page_num = self.length >> SE_PAGE_SHIFT; - BitArray::new(page_num, AllocType::new_static())? - } - }; + let page_num = self.length >> SE_PAGE_SHIFT; + let eaccept_map = BitArray::new(page_num, self.alloc)?; self.eaccept_map = Some(eaccept_map); Ok(()) } @@ -603,11 +548,15 @@ impl Ema { self.info = info; } - /// Obtain the allocator of ema - pub fn allocator(&self) -> AllocType { + pub fn alloc_type(&self) -> AllocType { self.alloc } + /// Obtain the allocator of ema + pub fn allocator(&self) -> &'static dyn Allocator { + self.alloc.alloctor() + } + pub fn flags(&self) -> AllocFlags { self.alloc_flags } @@ -634,7 +583,7 @@ impl EmaOptions { }, handler: None, priv_data: None, - alloc: AllocType::new_rsrv(), + alloc: AllocType::Reserve, } } @@ -700,16 +649,10 @@ impl EmaOptions { impl Ema { pub fn allocate(options: &EmaOptions, apply_now: bool) -> OsResult> { ensure!(options.addr.is_some(), EFAULT); - let mut new_ema = match options.alloc { - AllocType::Reserve(allocator) => { - let new_ema = Box::::new_in(Ema::new_options(options)?, allocator); - unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } - } - AllocType::Static(allocator) => { - let new_ema = - Box::::new_in(Ema::new_options(options)?, allocator); - unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } - } + let mut new_ema = { + let allocator = options.alloc.alloctor(); + let new_ema = Box::new_in(Ema::new(options)?, allocator); + unsafe { UnsafeRef::from_raw(Box::into_raw(new_ema)) } }; if apply_now { new_ema.alloc()?; diff --git a/sgx_trts/src/emm/init.rs b/sgx_trts/src/emm/init.rs index 0a8618a5d..04d861368 100644 --- a/sgx_trts/src/emm/init.rs +++ b/sgx_trts/src/emm/init.rs @@ -24,13 +24,7 @@ pub fn init_emm() { init_reserve_alloc(); } -cfg_if! { - if #[cfg(not(any(feature = "sim", feature = "hyper")))] { - pub use hw::*; - } else { - pub use sw::*; - } -} +pub use hw::*; #[cfg(not(any(feature = "sim", feature = "hyper")))] mod hw { @@ -67,7 +61,7 @@ mod hw { step, )?; } - } else { + } else if layout.entry.id != arch::LAYOUT_ID_USER_REGION { build_rts_context_emas(&layout.entry, offset)?; } } @@ -76,10 +70,6 @@ mod hw { } fn build_rts_context_emas(entry: &LayoutEntry, offset: usize) -> SgxResult { - if entry.id == arch::LAYOUT_ID_USER_REGION { - return Ok(()); - } - let rva = offset + (entry.rva as usize); assert!(is_page_aligned!(rva)); @@ -226,29 +216,28 @@ mod hw { let text_relo = parse::has_text_relo()?; let base = MmLayout::image_base(); - for phdr in elf.program_iter() { - let typ = phdr.get_type().unwrap_or(Type::Null); - - if typ == Type::Load { - let mut perm = ProtFlags::R; - let start = base + trim_to_page!(phdr.virtual_addr() as usize); - let end = - base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); - - if phdr.flags().is_write() || text_relo { - perm |= ProtFlags::W; - } - if phdr.flags().is_execute() { - perm |= ProtFlags::X; - } - - let mut options = EmaOptions::new(Some(start), end - start, AllocFlags::SYSTEM); - options.info(PageInfo { - typ: PageType::Reg, - prot: perm, - }); - mm_init_static_region(&options).map_err(|_| SgxStatus::Unexpected)?; + for phdr in elf + .program_iter() + .filter(|phdr| phdr.get_type().unwrap_or(Type::Null) == Type::Load) + { + let mut perm = ProtFlags::R; + let start = base + trim_to_page!(phdr.virtual_addr() as usize); + let end = + base + round_to_page!(phdr.virtual_addr() as usize + phdr.mem_size() as usize); + + if phdr.flags().is_write() || text_relo { + perm |= ProtFlags::W; } + if phdr.flags().is_execute() { + perm |= ProtFlags::X; + } + + let mut options = EmaOptions::new(Some(start), end - start, AllocFlags::SYSTEM); + options.info(PageInfo { + typ: PageType::Reg, + prot: perm, + }); + mm_init_static_region(&options).map_err(|_| SgxStatus::Unexpected)?; } Ok(()) diff --git a/sgx_trts/src/emm/page.rs b/sgx_trts/src/emm/page.rs index be5ca13b6..af08e7a91 100644 --- a/sgx_trts/src/emm/page.rs +++ b/sgx_trts/src/emm/page.rs @@ -18,13 +18,13 @@ use crate::arch::{SecInfo, SE_PAGE_SHIFT, SE_PAGE_SIZE}; use crate::enclave::is_within_enclave; use crate::inst::EncluInst; -use bitflags::bitflags; use core::num::NonZeroUsize; use sgx_tlibc_sys::{EFAULT, EINVAL}; use sgx_types::error::OsResult; use sgx_types::marker::ContiguousMemory; -bitflags! { +impl_bitflags! { + #[derive(Copy, Clone)] pub struct AllocFlags: u32 { const RESERVED = 0b0001; const COMMIT_NOW = 0b0010; diff --git a/sgx_trts/src/emm/tcs.rs b/sgx_trts/src/emm/tcs.rs index 4165e16b9..b1dd19fa5 100644 --- a/sgx_trts/src/emm/tcs.rs +++ b/sgx_trts/src/emm/tcs.rs @@ -63,8 +63,10 @@ pub fn mktcs(mk_tcs: NonNull) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] mod hw { use crate::arch::{self, Layout, Tcs}; + use crate::emm::mm_dealloc; use crate::emm::page::PageType; use crate::emm::{mm_commit, mm_modify_type}; + use crate::enclave::state::{self, State}; use crate::enclave::MmLayout; use crate::tcs::list; use core::ptr; @@ -132,6 +134,21 @@ mod hw { Ok(()) } + #[inline] + pub fn trim_tcs(tcs: &Tcs) -> SgxResult { + let mut list_guard = list::TCS_LIST.lock(); + for tcs in list_guard.iter_mut().filter(|&t| !ptr::eq(t.as_ptr(), tcs)) { + let result = mm_dealloc(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE); + if result.is_err() { + state::set_state(State::Crashed); + bail!(SgxStatus::Unexpected); + } + } + + list_guard.clear(); + Ok(()) + } + fn reentrant_add_static_tcs(table: &[Layout], offset: usize) -> SgxResult { let base = MmLayout::image_base(); unsafe { diff --git a/sgx_trts/src/emm/vmmgr.rs b/sgx_trts/src/emm/vmmgr.rs index 7722ac127..767d54b7e 100644 --- a/sgx_trts/src/emm/vmmgr.rs +++ b/sgx_trts/src/emm/vmmgr.rs @@ -270,14 +270,9 @@ impl VmMgr { ema.dealloc()?; // Drop inner Ema inexplicitly - match ema.allocator() { - AllocType::Reserve(allocator) => { - let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), allocator) }; - } - AllocType::Static(allocator) => { - let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), allocator) }; - } - } + let allocator = ema.allocator(); + let _ema_box = unsafe { Box::from_raw_in(UnsafeRef::into_raw(ema), allocator) }; + ema_num -= 1; } Ok(()) @@ -314,7 +309,7 @@ impl VmMgr { while count != 0 { let ema = cursor.get().unwrap(); // Ema must be reserved and can not manage internal memory region - if !ema.flags().contains(AllocFlags::RESERVED) || ema.allocator() != alloc { + if !ema.flags().contains(AllocFlags::RESERVED) || ema.alloc_type() != alloc { return None; } cursor.move_next(); diff --git a/sgx_trts/src/enclave/mem.rs b/sgx_trts/src/enclave/mem.rs index 8d922810a..e221cafe5 100644 --- a/sgx_trts/src/enclave/mem.rs +++ b/sgx_trts/src/enclave/mem.rs @@ -407,6 +407,9 @@ impl UserRegionMem { } pub fn is_within_rts_range(start: usize, len: usize) -> bool { + if !is_within_enclave(start as *const u8, len) { + return false; + } let end = if len > 0 { if let Some(end) = start.checked_add(len - 1) { end @@ -424,6 +427,9 @@ pub fn is_within_rts_range(start: usize, len: usize) -> bool { } pub fn is_within_user_range(start: usize, len: usize) -> bool { + if !is_within_enclave(start as *const u8, len) { + return false; + } let end = if len > 0 { if let Some(end) = start.checked_add(len - 1) { end diff --git a/sgx_trts/src/enclave/uninit.rs b/sgx_trts/src/enclave/uninit.rs index 04e654f47..aaee25273 100644 --- a/sgx_trts/src/enclave/uninit.rs +++ b/sgx_trts/src/enclave/uninit.rs @@ -15,11 +15,10 @@ // specific language governing permissions and limitations // under the License.. -use crate::arch; -use crate::emm::mm_dealloc; +use crate::emm::tcs::trim_tcs; use crate::enclave::state::{self, State}; use crate::enclave::{atexit, parse}; -use crate::tcs::{list, ThreadControl}; +use crate::tcs::ThreadControl; use core::sync::atomic::AtomicBool; use sgx_types::error::SgxResult; @@ -82,16 +81,7 @@ pub fn rtuninit(tc: ThreadControl) -> SgxResult { #[cfg(not(any(feature = "sim", feature = "hyper")))] { if SysFeatures::get().is_edmm() { - let mut list_guard = list::TCS_LIST.lock(); - for tcs in list_guard.iter_mut().filter(|&t| !ptr::eq(t.as_ptr(), tcs)) { - let result = mm_dealloc(tcs.as_ptr() as usize, arch::SE_PAGE_SIZE); - if result.is_err() { - state::set_state(State::Crashed); - bail!(SgxStatus::Unexpected); - } - } - - list_guard.clear(); + trim_tcs(tcs)?; } } diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs index 184bf2a59..d4bc51f73 100644 --- a/sgx_trts/src/lib.rs +++ b/sgx_trts/src/lib.rs @@ -39,6 +39,8 @@ #![feature(linked_list_cursors)] #![feature(strict_provenance)] #![feature(pointer_byte_offsets)] +#![feature(maybe_uninit_array_assume_init)] +#![feature(trait_upcasting)] #[cfg(all(feature = "sim", feature = "hyper"))] compile_error!("feature \"sim\" and feature \"hyper\" cannot be enabled at the same time"); From 5ba38bd718508ad10ed004d333f579921218c95c Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 1 Dec 2023 17:23:14 +0800 Subject: [PATCH 18/20] Implement Once and replace existed Once --- sgx_trts/src/emm/alloc.rs | 8 ++-- sgx_trts/src/emm/vmmgr.rs | 4 +- sgx_trts/src/se/report.rs | 54 +++------------------------ sgx_trts/src/sync/once.rs | 78 +++++++++++++++++++++++++++++++-------- 4 files changed, 74 insertions(+), 70 deletions(-) diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index d8e679381..bc1e7f700 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -22,13 +22,13 @@ use intrusive_collections::singly_linked_list::{Link, SinglyLinkedList}; use intrusive_collections::UnsafeRef; use sgx_tlibc_sys::ENOMEM; +use crate::sync::Once; use crate::sync::SpinMutex as Mutex; use core::alloc::{AllocError, Allocator, Layout}; use core::any::Any; use core::mem::size_of; use core::mem::MaybeUninit; use core::ptr::NonNull; -use spin::Once; use super::ema::EmaOptions; use super::page::AllocFlags; @@ -64,21 +64,21 @@ static RSRV_ALLOCATOR: Once> = Once::new(); /// Init lowest level static memory allocator pub fn init_static_alloc() { - STATIC.call_once(|| { + let _ = STATIC.call_once(|| { let static_alloc = LockedHeap::empty(); unsafe { static_alloc .lock() .init(STATIC_MEM.as_ptr() as usize, STATIC_MEM_SIZE) }; - static_alloc + Ok(static_alloc) }); } /// Init reserve memory allocator /// init_reserve_alloc() need to be called after init_static_alloc() pub fn init_reserve_alloc() { - RSRV_ALLOCATOR.call_once(|| Mutex::new(Reserve::new(INIT_MEM_SIZE))); + let _ = RSRV_ALLOCATOR.call_once(|| Ok(Mutex::new(Reserve::new(INIT_MEM_SIZE)))); } pub trait EmmAllocator: Allocator + Any { diff --git a/sgx_trts/src/emm/vmmgr.rs b/sgx_trts/src/emm/vmmgr.rs index 767d54b7e..072dd3341 100644 --- a/sgx_trts/src/emm/vmmgr.rs +++ b/sgx_trts/src/emm/vmmgr.rs @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License.. +use crate::sync::Once; use crate::{ arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}, emm::{PageType, ProtFlags}, @@ -28,7 +29,6 @@ use intrusive_collections::{ }; use sgx_tlibc_sys::{EEXIST, EINVAL, ENOMEM, EPERM}; use sgx_types::error::OsResult; -use spin::Once; use super::{ alloc::AllocType, @@ -51,7 +51,7 @@ pub(crate) static VMMGR: Once> = Once::new(); /// Initialize range management pub fn init_vmmgr() { - VMMGR.call_once(|| SpinReentrantMutex::new(VmMgr::new())); + let _ = VMMGR.call_once(|| Ok(SpinReentrantMutex::new(VmMgr::new()))); } pub fn mm_init_static_region(options: &EmaOptions) -> OsResult { diff --git a/sgx_trts/src/se/report.rs b/sgx_trts/src/se/report.rs index 2f8079496..0d21b2212 100644 --- a/sgx_trts/src/se/report.rs +++ b/sgx_trts/src/se/report.rs @@ -26,15 +26,11 @@ use core::ptr; use sgx_types::error::{SgxResult, SgxStatus}; use sgx_types::marker::ContiguousMemory; use sgx_types::types::{ - Attributes, AttributesFlags, ConfigId, CpuSvn, Key128bit, KeyId, KeyName, KeyRequest, Mac, - Measurement, MiscSelect, Report, Report2Mac, ReportBody, ReportData, TargetInfo, + Key128bit, KeyName, KeyRequest, Mac, Report, Report2Mac, ReportBody, ReportData, TargetInfo, }; use sgx_types::types::{ - CONFIGID_SIZE, CPUSVN_SIZE, HASH_SIZE, ISVEXT_PROD_ID_SIZE, ISV_FAMILY_ID_SIZE, KEYID_SIZE, - MAC_SIZE, REPORT2_MAC_RESERVED1_BYTES, REPORT2_MAC_RESERVED2_BYTES, - REPORT_BODY_RESERVED1_BYTES, REPORT_BODY_RESERVED2_BYTES, REPORT_BODY_RESERVED3_BYTES, - REPORT_BODY_RESERVED4_BYTES, REPORT_DATA_SIZE, TEE_REPORT2_SUBTYPE, TEE_REPORT2_TYPE, - TEE_REPORT2_VERSION, TEE_REPORT2_VERSION_SERVICETD, + REPORT2_MAC_RESERVED1_BYTES, REPORT2_MAC_RESERVED2_BYTES, TEE_REPORT2_SUBTYPE, + TEE_REPORT2_TYPE, TEE_REPORT2_VERSION, TEE_REPORT2_VERSION_SERVICETD, }; #[repr(C, align(128))] @@ -58,51 +54,11 @@ unsafe impl ContiguousMemory for AlignTargetInfo {} unsafe impl ContiguousMemory for AlignReport {} unsafe impl ContiguousMemory for AlignReport2Mac {} -static SELF_REPORT: Once = Once::new(); -static mut REPORT: AlignReport = AlignReport(Report { - body: ReportBody { - cpu_svn: CpuSvn { - svn: [0; CPUSVN_SIZE], - }, - misc_select: MiscSelect::empty(), - reserved1: [0; REPORT_BODY_RESERVED1_BYTES], - isv_ext_prod_id: [0; ISVEXT_PROD_ID_SIZE], - attributes: Attributes { - flags: AttributesFlags::empty(), - xfrm: 0, - }, - mr_enclave: Measurement { m: [0; HASH_SIZE] }, - reserved2: [0; REPORT_BODY_RESERVED2_BYTES], - mr_signer: Measurement { m: [0; HASH_SIZE] }, - reserved3: [0; REPORT_BODY_RESERVED3_BYTES], - config_id: ConfigId { - id: [0; CONFIGID_SIZE], - }, - isv_prod_id: 0, - isv_svn: 0, - config_svn: 0, - reserved4: [0; REPORT_BODY_RESERVED4_BYTES], - isv_family_id: [0; ISV_FAMILY_ID_SIZE], - report_data: ReportData { - d: [0; REPORT_DATA_SIZE], - }, - }, - key_id: KeyId { - id: [0_u8; KEYID_SIZE], - }, - mac: [0_u8; MAC_SIZE], -}); +static REPORT: Once = Once::new(); impl AlignReport { pub fn get_self() -> &'static AlignReport { - unsafe { - let _ = SELF_REPORT.call_once(|| { - let report = AlignReport::for_self()?; - REPORT = report; - Ok(()) - }); - &REPORT - } + REPORT.call_once(|| AlignReport::for_self()).unwrap() } pub fn for_self() -> SgxResult { diff --git a/sgx_trts/src/sync/once.rs b/sgx_trts/src/sync/once.rs index 3261f0113..14424385e 100644 --- a/sgx_trts/src/sync/once.rs +++ b/sgx_trts/src/sync/once.rs @@ -16,46 +16,94 @@ // under the License.. use crate::sync::{SpinMutex, SpinMutexGuard}; -use core::sync::atomic::{AtomicUsize, Ordering}; +use core::{ + cell::UnsafeCell, + mem::MaybeUninit, + sync::atomic::{AtomicUsize, Ordering}, +}; use sgx_types::error::SgxResult; -pub struct Once { +pub struct Once { lock: SpinMutex<()>, state: AtomicUsize, + data: UnsafeCell>, } -unsafe impl Sync for Once {} -unsafe impl Send for Once {} +impl Default for Once { + fn default() -> Self { + Self::new() + } +} + +unsafe impl Sync for Once {} +unsafe impl Send for Once {} const INCOMPLETE: usize = 0x0; const COMPLETE: usize = 0x1; -impl Once { - pub const fn new() -> Once { - Once { - lock: SpinMutex::new(()), - state: AtomicUsize::new(INCOMPLETE), - } +impl Once { + /// Initialization constant of [`Once`]. + #[allow(clippy::declare_interior_mutable_const)] + pub const INIT: Self = Self { + lock: SpinMutex::new(()), + state: AtomicUsize::new(INCOMPLETE), + data: UnsafeCell::new(MaybeUninit::uninit()), + }; + + /// Creates a new [`Once`]. + pub const fn new() -> Self { + Self::INIT } pub fn lock(&self) -> SpinMutexGuard<()> { self.lock.lock() } - pub fn call_once(&self, init: F) -> SgxResult + pub fn call_once(&self, init: F) -> SgxResult<&T> where - F: FnOnce() -> SgxResult, + F: FnOnce() -> SgxResult, { if self.is_completed() { - return Ok(()); + return Ok(unsafe { + // SAFETY: The status is Complete + self.force_get() + }); } let _guard = self.lock.lock(); if !self.is_completed() { - init()?; + let val = init()?; + unsafe { + (*self.data.get()).as_mut_ptr().write(val); + } self.state.store(COMPLETE, Ordering::Release); } - Ok(()) + unsafe { Ok(self.force_get()) } + } + + /// Returns a reference to the inner value if the [`Once`] has been initialized. + pub fn get(&self) -> Option<&T> { + if self.state.load(Ordering::Acquire) == COMPLETE { + Some(unsafe { self.force_get() }) + } else { + None + } + } + + /// Get a reference to the initialized instance. Must only be called once COMPLETE. + unsafe fn force_get(&self) -> &T { + // SAFETY: + // * `UnsafeCell`/inner deref: data never changes again + // * `MaybeUninit`/outer deref: data was initialized + &*(*self.data.get()).as_ptr() + } + + /// Get a reference to the initialized instance. Must only be called once COMPLETE. + unsafe fn force_get_mut(&mut self) -> &mut T { + // SAFETY: + // * `UnsafeCell`/inner deref: data never changes again + // * `MaybeUninit`/outer deref: data was initialized + &mut *(*self.data.get()).as_mut_ptr() } #[inline] From 7438c5806671341f7442edf7bc5a80c4004a0c53 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 15 Dec 2023 15:14:04 +0800 Subject: [PATCH 19/20] Refactor block in emm --- sgx_trts/Cargo.toml | 3 +- sgx_trts/src/emm/alloc.rs | 84 +++++++++++++++++++++++++-------------- sgx_trts/src/emm/ema.rs | 4 +- sgx_trts/src/se/report.rs | 2 +- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml index 9c49f4aff..cb8ce89a1 100644 --- a/sgx_trts/Cargo.toml +++ b/sgx_trts/Cargo.toml @@ -41,8 +41,7 @@ sgx_types = { path = "../sgx_types" } sgx_crypto_sys = { path = "../sgx_crypto/sgx_crypto_sys" } sgx_tlibc_sys = { path = "../sgx_libc/sgx_tlibc_sys" } -intrusive-collections = { git = "https://github.com/ClawSeven/intrusive-rs.git", rev = "6d34cd7" } -# intrusive-collections = { git = "https://github.com/ClawSeven/intrusive-rs.git", rev = "3db5618" } +intrusive-collections = { git = "https://github.com/ClawSeven/intrusive-rs.git", rev = "152317d" } buddy_system_allocator = "0.9.0" spin = "0.9.4" bitflags = "1.3" diff --git a/sgx_trts/src/emm/alloc.rs b/sgx_trts/src/emm/alloc.rs index bc1e7f700..8388c494e 100644 --- a/sgx_trts/src/emm/alloc.rs +++ b/sgx_trts/src/emm/alloc.rs @@ -199,7 +199,7 @@ struct BlockFree { #[derive(Debug)] struct BlockUsed { size: usize, - payload: usize, + payload: usize, // Act as placeholder } impl BlockFree { @@ -217,6 +217,10 @@ impl BlockFree { fn block_size(&self) -> usize { self.size & SIZE_MASK } + + fn clear_alloced(&mut self) { + self.size &= SIZE_MASK; + } } impl BlockUsed { @@ -243,6 +247,43 @@ impl BlockUsed { fn clear_alloced(&mut self) { self.size &= SIZE_MASK; } + + // Return the ptr of payload + fn payload_ptr(&self) -> usize { + &self.payload as *const _ as usize + } + + unsafe fn with_payload<'a>(payload_ptr: usize) -> &'a mut BlockUsed { + let payload_ptr = payload_ptr as *const u8; + let block = &mut *(payload_ptr.byte_offset(-(HEADER_SIZE as isize)) as *mut BlockUsed); + block + } +} + +impl<'a> From<&'a mut BlockFree> for &'a mut BlockUsed { + fn from(block_free: &'a mut BlockFree) -> Self { + let block_used = unsafe { &mut *(block_free as *mut _ as *mut BlockUsed) }; + + block_used.size = block_free.block_size(); + // Clear residual link information + block_used.payload = 0; + block_used.set_alloced(); + + block_used + } +} + +impl<'a> From<&'a mut BlockUsed> for &'a mut BlockFree { + fn from(block_used: &'a mut BlockUsed) -> Self { + let block_free = unsafe { &mut *(block_used as *mut _ as *mut BlockFree) }; + + block_free.size = block_used.block_size(); + block_free.link = Link::new(); + // Useless method to mark free tag + block_free.clear_alloced(); + + block_free + } } intrusive_adapter!(BlockFreeAda = UnsafeRef: BlockFree { link: Link }); @@ -367,36 +408,21 @@ impl Reserve { idx } - // Reconstruct BlockUsed with BlockFree block_size() and set alloc, return payload addr. - // BlockFree -> BlockUsed -> Payload addr (Used) - fn block_to_payload(&self, block: UnsafeRef) -> usize { - let block_size = block.block_size(); - let mut block_used = BlockUsed::new(block_size); - block_used.set_alloced(); - - let block_used_ptr = UnsafeRef::into_raw(block) as *mut BlockUsed; - unsafe { - block_used_ptr.write(block_used); - // Regular offset shifts count*T bytes - block_used_ptr.byte_offset(HEADER_SIZE as isize) as usize - } + // Reconstruct BlockUsed with BlockFree block_size() and set alloc, return payload ptr. + // BlockFree -> BlockUsed -> Payload ptr (Used) + fn block_to_payload(&self, mut block_free: UnsafeRef) -> usize { + // Inexplicily change inner data of pointer + let block_used: &mut BlockUsed = block_free.as_mut().into(); + block_used.payload_ptr() } - // Reconstruct a new BlockFree with BlockUsed block_size(), return payload addr. - // Payload addr (Used) -> BlockUsed -> BlockFree - fn payload_to_block(&self, payload_addr: usize) -> UnsafeRef { - let payload_ptr = payload_addr as *const u8; - let block_used_ptr = - unsafe { payload_ptr.byte_offset(-(HEADER_SIZE as isize)) as *mut BlockUsed }; - - // Implicitly clear alloc mask, reconstruct new BlockFree - let block_size = unsafe { block_used_ptr.read().block_size() }; - let block_free = BlockFree::new(block_size); - let block_free_ptr = block_used_ptr as *mut BlockFree; - unsafe { - block_free_ptr.write(block_free); - UnsafeRef::from_raw(block_free_ptr) - } + // Reconstruct a new BlockFree with BlockUsed block_size(), return payload ptr. + // Payload ptr (Used) -> BlockUsed -> BlockFree + fn payload_to_block(&self, payload_ptr: usize) -> UnsafeRef { + let block_used = unsafe { BlockUsed::with_payload(payload_ptr) }; + // Inexplicily change inner data of pointer + let block_free: &mut BlockFree = block_used.into(); + unsafe { UnsafeRef::from_raw(block_free as *const BlockFree) } } /// Malloc memory diff --git a/sgx_trts/src/emm/ema.rs b/sgx_trts/src/emm/ema.rs index bb36be17b..f26e3f9bf 100644 --- a/sgx_trts/src/emm/ema.rs +++ b/sgx_trts/src/emm/ema.rs @@ -16,10 +16,10 @@ // under the License.. use crate::arch::{SE_PAGE_SHIFT, SE_PAGE_SIZE}; +use crate::emm::alloc::EmmAllocator; use crate::emm::{PageInfo, PageRange, PageType, ProtFlags}; use crate::enclave::is_within_enclave; use alloc::boxed::Box; -use core::alloc::Allocator; use intrusive_collections::{intrusive_adapter, LinkedListLink, UnsafeRef}; use sgx_tlibc_sys::{c_void, EACCES, EFAULT, EINVAL}; use sgx_types::error::OsResult; @@ -553,7 +553,7 @@ impl Ema { } /// Obtain the allocator of ema - pub fn allocator(&self) -> &'static dyn Allocator { + pub fn allocator(&self) -> &'static dyn EmmAllocator { self.alloc.alloctor() } diff --git a/sgx_trts/src/se/report.rs b/sgx_trts/src/se/report.rs index 0d21b2212..9eab4eaed 100644 --- a/sgx_trts/src/se/report.rs +++ b/sgx_trts/src/se/report.rs @@ -58,7 +58,7 @@ static REPORT: Once = Once::new(); impl AlignReport { pub fn get_self() -> &'static AlignReport { - REPORT.call_once(|| AlignReport::for_self()).unwrap() + REPORT.call_once(AlignReport::for_self).unwrap() } pub fn for_self() -> SgxResult { From 9fc99383991c7688497558529b183ee60e1319d7 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Fri, 23 Feb 2024 17:26:30 +0800 Subject: [PATCH 20/20] Fix emm samplecode compilation with BUILD_STD=cargo --- samplecode/emm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samplecode/emm/Makefile b/samplecode/emm/Makefile index f1a3e1189..a1e4431e5 100644 --- a/samplecode/emm/Makefile +++ b/samplecode/emm/Makefile @@ -93,7 +93,7 @@ Rust_Target_Path := $(ROOT_DIR)/rustlib ifeq ($(BUILD_STD), cargo) Rust_Build_Std := $(Rust_Build_Flags) -Zbuild-std=core,alloc - Rust_Std_Features := + Rust_Std_Features := --features thread Rust_Target_Flags := --target $(Rust_Target_Path)/$(Rust_Build_Target).json Rust_Sysroot_Path := $(CURDIR)/sysroot Rust_Sysroot_Flags := RUSTFLAGS="--sysroot $(Rust_Sysroot_Path)"