Use low level API to replace sgx_mm_(commit/commit_data/modify_permissions)
Reduce the EMA management overhead and the global lock of emm module of Intel SGX SDK
This commit is contained in:
parent
d7131a1a5b
commit
6930e606ef
@ -48,6 +48,7 @@ dcap = [] # DCAP support. The compilation relies on DCAP package.
|
||||
cov = ["sgx_cov"] # Enable coverage colletcion.
|
||||
hyper_mode = [] # For running in hyper mode.
|
||||
pku = [] # PKU Support
|
||||
sim_mode = [] # For running in SGX simulation mode
|
||||
|
||||
[target.'cfg(not(target_env = "sgx"))'.dependencies]
|
||||
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" }
|
||||
|
@ -61,7 +61,12 @@ else
|
||||
endif
|
||||
|
||||
LIBOS_CORE_A := $(OBJ_DIR)/libos/lib/lib$(LIBOS_CORE_LIB_NAME).a
|
||||
LIBOS_CORE_RS_A := $(OBJ_DIR)/libos/lib/libocclum_libos_core_rs.a
|
||||
|
||||
ifeq ($(SGX_MODE), SIM)
|
||||
LIBOS_CORE_RS_A := $(OBJ_DIR)/libos/lib/libocclum_libos_core_rs_sim.a
|
||||
else
|
||||
LIBOS_CORE_RS_A := $(OBJ_DIR)/libos/lib/libocclum_libos_core_rs.a
|
||||
endif
|
||||
|
||||
# All source code
|
||||
RUST_SRCS := $(wildcard src/*.rs src/*/*.rs src/*/*/*.rs src/*/*/*/*.rs src/*/*/*/*/*.rs)
|
||||
@ -140,20 +145,27 @@ ifeq ($(SGX_MODE), HYPER)
|
||||
LIBOS_FEATURES += hyper_mode
|
||||
endif
|
||||
|
||||
ifeq ($(SGX_MODE), SIM)
|
||||
LIBOS_FEATURES += sim_mode
|
||||
endif
|
||||
|
||||
# Release build is for production use. We enable code coverage only for debug
|
||||
# build. It also simplifies the implementation as the release and debug build
|
||||
# have different output paths.
|
||||
ifeq ($(OCCLUM_RELEASE_BUILD), 1)
|
||||
$(LIBOS_CORE_RS_A): $(RUST_SRCS)
|
||||
@RUSTC_BOOTSTRAP=1 RUSTC_WRAPPER=$(RUSTC_WRAPPER) cargo build --release --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR) --features "$(LIBOS_FEATURES)"
|
||||
@mv $(OBJ_DIR)/libos/lib/libocclum_libos_core_rs.a $@ || true
|
||||
@echo "CARGO (release) => $@"
|
||||
else ifneq ($(OCCLUM_COV),)
|
||||
$(LIBOS_CORE_RS_A): $(RUST_SRCS)
|
||||
@CARGO_INCREMENTAL=0 RUSTC_BOOTSTRAP=1 RUSTFLAGS=$(COV_FLAGS) cargo build --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR) --features "$(LIBOS_FEATURES)"
|
||||
@mv $(OBJ_DIR)/libos/lib/libocclum_libos_core_rs.a $@ || true
|
||||
@echo "CARGO (debug + cov) => $@"
|
||||
else
|
||||
$(LIBOS_CORE_RS_A): $(RUST_SRCS)
|
||||
@RUSTC_BOOTSTRAP=1 RUSTC_WRAPPER=$(RUSTC_WRAPPER) cargo build --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR) --features "$(LIBOS_FEATURES)"
|
||||
@mv $(OBJ_DIR)/libos/lib/libocclum_libos_core_rs.a $@ || true
|
||||
@echo "CARGO (debug) => $@"
|
||||
endif
|
||||
|
||||
|
@ -282,6 +282,6 @@ impl ShmManager {
|
||||
return;
|
||||
}
|
||||
vma.set_perms(perms);
|
||||
vma.modify_permissions_for_committed_pages(perms);
|
||||
vma.modify_permissions_for_committed_pages(old_perms, perms);
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ impl VMArea {
|
||||
|
||||
// Set memory permissions
|
||||
if !options.perms().is_default() {
|
||||
vm_area.modify_protection_force(None, vm_area.perms());
|
||||
vm_area.modify_protection_force(None, VMPerms::DEFAULT, vm_area.perms());
|
||||
}
|
||||
}
|
||||
// Do nothing if this vma has no committed memory
|
||||
@ -274,7 +274,7 @@ impl VMArea {
|
||||
debug_assert!(self.range().is_superset_of(target_range));
|
||||
let buf = unsafe { target_range.as_slice_mut() };
|
||||
if !self.perms().is_default() {
|
||||
self.modify_protection_force(Some(&target_range), VMPerms::default());
|
||||
self.modify_protection_force(Some(&target_range), self.perms(), VMPerms::default());
|
||||
}
|
||||
|
||||
if need_flush {
|
||||
@ -296,13 +296,17 @@ impl VMArea {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_permissions_for_committed_pages(&self, new_perms: VMPerms) {
|
||||
pub fn modify_permissions_for_committed_pages(
|
||||
&self,
|
||||
current_perms: VMPerms,
|
||||
new_perms: VMPerms,
|
||||
) {
|
||||
if self.is_fully_committed() {
|
||||
self.modify_protection_force(None, new_perms);
|
||||
self.modify_protection_force(None, current_perms, new_perms);
|
||||
} else if self.is_partially_committed() {
|
||||
let committed = true;
|
||||
for range in self.pages().get_ranges(committed) {
|
||||
self.modify_protection_force(Some(&range), new_perms);
|
||||
self.modify_protection_force(Some(&range), current_perms, new_perms);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -638,11 +642,21 @@ impl VMArea {
|
||||
// Current implementation with "unwrap()" can help us find the error quickly by panicing directly. Also, restoring VM state
|
||||
// when this function fails will require some work and is not that simple.
|
||||
// TODO: Return with Result instead of "unwrap()"" in this function.
|
||||
fn modify_protection_force(&self, protect_range: Option<&VMRange>, new_perms: VMPerms) {
|
||||
fn modify_protection_force(
|
||||
&self,
|
||||
protect_range: Option<&VMRange>,
|
||||
current_perms: VMPerms,
|
||||
new_perms: VMPerms,
|
||||
) {
|
||||
let protect_range = protect_range.unwrap_or_else(|| self.range());
|
||||
|
||||
self.epc_type
|
||||
.modify_protection(protect_range.start(), protect_range.size(), new_perms)
|
||||
.modify_protection(
|
||||
protect_range.start(),
|
||||
protect_range.size(),
|
||||
current_perms,
|
||||
new_perms,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@ -668,7 +682,7 @@ impl VMArea {
|
||||
}
|
||||
VMInitializer::DoNothing() => {
|
||||
if !self.perms().is_default() {
|
||||
self.modify_protection_force(Some(target_range), perms);
|
||||
self.modify_protection_force(Some(target_range), VMPerms::DEFAULT, perms);
|
||||
}
|
||||
}
|
||||
VMInitializer::FillZeros() => {
|
||||
@ -677,7 +691,7 @@ impl VMArea {
|
||||
buf.iter_mut().for_each(|b| *b = 0);
|
||||
}
|
||||
if !perms.is_default() {
|
||||
self.modify_protection_force(Some(target_range), perms);
|
||||
self.modify_protection_force(Some(target_range), VMPerms::DEFAULT, perms);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
@ -732,7 +746,7 @@ impl VMArea {
|
||||
.map_err(|_| errno!(EACCES, "failed to init memory from file"))?;
|
||||
|
||||
if !new_perm.is_default() {
|
||||
self.modify_protection_force(Some(target_range), new_perm);
|
||||
self.modify_protection_force(Some(target_range), VMPerms::DEFAULT, new_perm);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -766,8 +780,6 @@ impl VMArea {
|
||||
range.resize(commit_once_size - total_commit_size);
|
||||
}
|
||||
|
||||
// We don't take care the file-backed memory here
|
||||
debug_assert!(self.backed_file().is_none());
|
||||
self.init_memory_internal(&range, None)?;
|
||||
|
||||
total_commit_size += range.size();
|
||||
@ -787,7 +799,6 @@ impl VMArea {
|
||||
// Only used to handle PF triggered by the kernel
|
||||
fn commit_current_vma_whole(&mut self) -> Result<()> {
|
||||
debug_assert!(!self.is_fully_committed());
|
||||
debug_assert!(self.backed_file().is_none());
|
||||
|
||||
let mut uncommitted_ranges = self.pages.as_ref().unwrap().get_ranges(false);
|
||||
for range in uncommitted_ranges {
|
||||
@ -797,35 +808,6 @@ impl VMArea {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: We can re-enable this when we support lazy extend permissions.
|
||||
#[allow(dead_code)]
|
||||
fn page_fault_handler_extend_permission(&mut self, pf_addr: usize) -> Result<()> {
|
||||
let permission = self.perms();
|
||||
|
||||
// This is intended by the application.
|
||||
if permission == VMPerms::NONE {
|
||||
return_errno!(EPERM, "trying to access PROT_NONE memory");
|
||||
}
|
||||
|
||||
if self.is_fully_committed() {
|
||||
self.modify_protection_force(None, permission);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let committed = true;
|
||||
let committed_ranges = self.pages().get_ranges(committed);
|
||||
for range in committed_ranges.iter() {
|
||||
if !range.contains(pf_addr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.epc_type
|
||||
.modify_protection(range.start(), range.size(), permission)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for VMArea {
|
||||
|
@ -293,7 +293,8 @@ impl ChunkManager {
|
||||
if intersection_vma.range() == containing_vma.range() {
|
||||
// The whole containing_vma is mprotected
|
||||
containing_vma.set_perms(new_perms);
|
||||
containing_vma.modify_permissions_for_committed_pages(containing_vma.perms());
|
||||
containing_vma
|
||||
.modify_permissions_for_committed_pages(old_perms, containing_vma.perms());
|
||||
containing_vmas.replace_with(VMAObj::new_vma_obj(containing_vma));
|
||||
containing_vmas.move_next();
|
||||
continue;
|
||||
@ -317,7 +318,10 @@ impl ChunkManager {
|
||||
new_perms,
|
||||
VMAccess::Private(current_pid),
|
||||
);
|
||||
new_vma.modify_permissions_for_committed_pages(new_vma.perms());
|
||||
new_vma.modify_permissions_for_committed_pages(
|
||||
containing_vma.perms(),
|
||||
new_vma.perms(),
|
||||
);
|
||||
let new_vma = VMAObj::new_vma_obj(new_vma);
|
||||
|
||||
// Another new VMA
|
||||
@ -351,7 +355,10 @@ impl ChunkManager {
|
||||
VMAccess::Private(current_pid),
|
||||
);
|
||||
|
||||
new_vma.modify_permissions_for_committed_pages(new_vma.perms());
|
||||
new_vma.modify_permissions_for_committed_pages(
|
||||
containing_vma.perms(),
|
||||
new_vma.perms(),
|
||||
);
|
||||
|
||||
if remain_vma.start() == containing_vma.start() {
|
||||
// mprotect right side of the vma
|
||||
|
@ -69,7 +69,12 @@ pub trait EPCAllocator {
|
||||
return_errno!(ENOSYS, "operation not supported");
|
||||
}
|
||||
|
||||
fn modify_protection(addr: usize, length: usize, protection: VMPerms) -> Result<()> {
|
||||
fn modify_protection(
|
||||
addr: usize,
|
||||
length: usize,
|
||||
current_protection: VMPerms,
|
||||
new_protection: VMPerms,
|
||||
) -> Result<()> {
|
||||
return_errno!(ENOSYS, "operation not supported");
|
||||
}
|
||||
|
||||
@ -99,11 +104,16 @@ impl EPCAllocator for ReservedMem {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modify_protection(addr: usize, length: usize, protection: VMPerms) -> Result<()> {
|
||||
fn modify_protection(
|
||||
addr: usize,
|
||||
length: usize,
|
||||
current_protection: VMPerms,
|
||||
new_protection: VMPerms,
|
||||
) -> Result<()> {
|
||||
let mut ret_val = 0;
|
||||
let ret = if rsgx_is_supported_EDMM() {
|
||||
unsafe {
|
||||
sgx_tprotect_rsrv_mem(addr as *const c_void, length, protection.bits() as i32)
|
||||
sgx_tprotect_rsrv_mem(addr as *const c_void, length, new_protection.bits() as i32)
|
||||
}
|
||||
} else {
|
||||
// For platforms without EDMM, sgx_tprotect_rsrv_mem is actually useless.
|
||||
@ -113,12 +123,13 @@ impl EPCAllocator for ReservedMem {
|
||||
&mut ret_val as *mut i32,
|
||||
addr as *const c_void,
|
||||
length,
|
||||
protection.bits() as i32,
|
||||
new_protection.bits() as i32,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if ret != sgx_status_t::SGX_SUCCESS || ret_val != 0 {
|
||||
error!("ocall ret = {:?}, ret_val = {:?}", ret, ret_val);
|
||||
return_errno!(ENOMEM, "reserved memory modify protection failure");
|
||||
}
|
||||
|
||||
@ -147,17 +158,26 @@ impl EPCAllocator for UserRegionMem {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modify_protection(addr: usize, length: usize, protection: VMPerms) -> Result<()> {
|
||||
fn modify_protection(
|
||||
addr: usize,
|
||||
length: usize,
|
||||
current_protection: VMPerms,
|
||||
new_protection: VMPerms,
|
||||
) -> Result<()> {
|
||||
trace!(
|
||||
"user region modify protection, protection = {:?}, range = {:?}",
|
||||
protection,
|
||||
new_protection,
|
||||
VMRange::new_with_size(addr, length).unwrap()
|
||||
);
|
||||
let ptr = NonNull::<u8>::new(addr as *mut u8).unwrap();
|
||||
unsafe {
|
||||
EmmAlloc.modify_permissions(ptr, length, Perm::from_bits(protection.bits()).unwrap())
|
||||
|
||||
// Simulation mode doesn't have the symbol used here
|
||||
#[cfg(not(feature = "sim_mode"))]
|
||||
{
|
||||
EDMMLocalApi::modify_permissions(addr, length, current_protection, new_protection)?;
|
||||
}
|
||||
.map_err(|e| errno!(Errno::from(e as u32)))?;
|
||||
|
||||
#[cfg(feature = "sim_mode")]
|
||||
unreachable!();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -169,8 +189,12 @@ impl EPCAllocator for UserRegionMem {
|
||||
|
||||
impl UserRegionMem {
|
||||
fn commit_memory(start_addr: usize, size: usize) -> Result<()> {
|
||||
let ptr = NonNull::<u8>::new(start_addr as *mut u8).unwrap();
|
||||
unsafe { EmmAlloc.commit(ptr, size) }.map_err(|e| errno!(Errno::from(e as u32)))?;
|
||||
#[cfg(not(feature = "sim_mode"))]
|
||||
EDMMLocalApi::commit_memory(start_addr, size)?;
|
||||
|
||||
#[cfg(feature = "sim_mode")]
|
||||
unreachable!();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -179,16 +203,19 @@ impl UserRegionMem {
|
||||
size: usize,
|
||||
new_perms: VMPerms,
|
||||
) -> Result<()> {
|
||||
let ptr = NonNull::<u8>::new(start_addr as *mut u8).unwrap();
|
||||
let perm = Perm::from_bits(new_perms.bits()).unwrap();
|
||||
if size == PAGE_SIZE {
|
||||
unsafe { EmmAlloc::commit_with_data(ptr, ZERO_PAGE.as_slice(), perm) }
|
||||
.map_err(|e| errno!(Errno::from(e as u32)))?;
|
||||
} else {
|
||||
let data = ZeroPage::new_page_aligned_vec(size);
|
||||
unsafe { EmmAlloc::commit_with_data(ptr, data.as_slice(), perm) }
|
||||
.map_err(|e| errno!(Errno::from(e as u32)))?;
|
||||
#[cfg(not(feature = "sim_mode"))]
|
||||
{
|
||||
if size == PAGE_SIZE {
|
||||
EDMMLocalApi::commit_with_data(start_addr, ZERO_PAGE.as_slice(), new_perms)?;
|
||||
} else {
|
||||
let data = ZeroPage::new_page_aligned_vec(size);
|
||||
EDMMLocalApi::commit_with_data(start_addr, data.as_slice(), new_perms)?;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sim_mode")]
|
||||
unreachable!();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -199,16 +226,19 @@ impl UserRegionMem {
|
||||
file_offset: usize,
|
||||
new_perms: VMPerms,
|
||||
) -> Result<()> {
|
||||
let mut data = ZeroPage::new_page_aligned_vec(size);
|
||||
let len = file
|
||||
.read_at(file_offset, data.as_mut_slice())
|
||||
.map_err(|_| errno!(EACCES, "failed to init memory from file"))?;
|
||||
#[cfg(not(feature = "sim_mode"))]
|
||||
{
|
||||
let mut data = ZeroPage::new_page_aligned_vec(size);
|
||||
let len = file
|
||||
.read_at(file_offset, data.as_mut_slice())
|
||||
.map_err(|_| errno!(EACCES, "failed to init memory from file"))?;
|
||||
|
||||
let ptr = NonNull::<u8>::new(start_addr as *mut u8).unwrap();
|
||||
let perm = Perm::from_bits(new_perms.bits()).unwrap();
|
||||
EDMMLocalApi::commit_with_data(start_addr, data.as_slice(), new_perms)?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "sim_mode")]
|
||||
unreachable!();
|
||||
|
||||
unsafe { EmmAlloc::commit_with_data(ptr, data.as_slice(), perm) }
|
||||
.map_err(|e| errno!(Errno::from(e as u32)))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -324,21 +354,33 @@ impl EPCMemType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_protection(&self, addr: usize, length: usize, protection: VMPerms) -> Result<()> {
|
||||
pub fn modify_protection(
|
||||
&self,
|
||||
addr: usize,
|
||||
length: usize,
|
||||
current_protection: VMPerms,
|
||||
new_protection: VMPerms,
|
||||
) -> Result<()> {
|
||||
// PT_GROWSDOWN should only be applied to stack segment or a segment mapped with the MAP_GROWSDOWN flag set.
|
||||
// Since the memory are managed by our own, mprotect ocall shouldn't use this flag. Otherwise, EINVAL will be thrown.
|
||||
let mut prot = protection.clone();
|
||||
let mut prot = new_protection;
|
||||
let mut current_prot = current_protection;
|
||||
prot.remove(VMPerms::GROWSDOWN);
|
||||
current_prot.remove(VMPerms::GROWSDOWN);
|
||||
|
||||
match self {
|
||||
EPCMemType::Reserved => ReservedMem::modify_protection(addr, length, prot),
|
||||
EPCMemType::UserRegion => UserRegionMem::modify_protection(addr, length, prot),
|
||||
EPCMemType::Reserved => {
|
||||
ReservedMem::modify_protection(addr, length, current_prot, prot)
|
||||
}
|
||||
EPCMemType::UserRegion => {
|
||||
UserRegionMem::modify_protection(addr, length, current_prot, prot)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit_memory(start_addr: usize, size: usize, new_perms: Option<VMPerms>) -> Result<()> {
|
||||
trace!(
|
||||
debug!(
|
||||
"commit epc: {:?}, new permission: {:?}",
|
||||
VMRange::new_with_size(start_addr, size).unwrap(),
|
||||
new_perms
|
||||
@ -397,4 +439,139 @@ extern "C" {
|
||||
len: usize,
|
||||
prot: i32,
|
||||
) -> sgx_status_t;
|
||||
|
||||
fn sgx_mm_modify_ocall(addr: usize, size: usize, flags_from: i32, flags_to: i32) -> i32;
|
||||
|
||||
// EACCEPT
|
||||
fn do_eaccept(si: *const sec_info_t, addr: usize) -> i32;
|
||||
|
||||
// EMODPE
|
||||
fn do_emodpe(si: *const sec_info_t, addr: usize) -> i32;
|
||||
|
||||
// EACCEPTCOPY
|
||||
fn do_eacceptcopy(si: *const sec_info_t, dest: usize, src: usize) -> i32;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C, align(512))]
|
||||
struct sec_info_t {
|
||||
flags: u64,
|
||||
reserved: [u64; 7],
|
||||
}
|
||||
|
||||
impl sec_info_t {
|
||||
const SGX_EMA_STATE_PENDING: u64 = 0x08; // pending state
|
||||
const SGX_EMA_STATE_PR: u64 = 0x20; // permission restriction state
|
||||
|
||||
fn new_for_modify_permission(new_protection: &VMPerms) -> Self {
|
||||
Self {
|
||||
flags: ((new_protection.bits() | SGX_EMA_PAGE_TYPE_REG) as u64)
|
||||
| Self::SGX_EMA_STATE_PR,
|
||||
reserved: [0; 7],
|
||||
}
|
||||
}
|
||||
|
||||
fn new_for_commit_memory() -> Self {
|
||||
Self {
|
||||
flags: ((VMPerms::DEFAULT.bits() | SGX_EMA_PAGE_TYPE_REG) as u64)
|
||||
| Self::SGX_EMA_STATE_PENDING,
|
||||
reserved: [0; 7],
|
||||
}
|
||||
}
|
||||
|
||||
fn new_for_commit_with_data(protection: &VMPerms) -> Self {
|
||||
Self {
|
||||
flags: (protection.bits() | SGX_EMA_PAGE_TYPE_REG) as u64,
|
||||
reserved: [0; 7],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "sim_mode"))]
|
||||
struct EDMMLocalApi;
|
||||
|
||||
#[cfg(not(feature = "sim_mode"))]
|
||||
impl EDMMLocalApi {
|
||||
// To replace sgx_mm_commit
|
||||
fn commit_memory(start_addr: usize, size: usize) -> Result<()> {
|
||||
let si = sec_info_t::new_for_commit_memory();
|
||||
for page in (start_addr..start_addr + size).step_by(PAGE_SIZE) {
|
||||
let ret = unsafe { do_eaccept(&si as *const sec_info_t, page) };
|
||||
if ret != 0 {
|
||||
return_errno!(EFAULT, "do_eaccept failure");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// To replace sgx_mm_commit_data
|
||||
fn commit_with_data(addr: usize, data: &[u8], perm: VMPerms) -> Result<()> {
|
||||
let si = sec_info_t::new_for_commit_with_data(&perm);
|
||||
let size = data.len();
|
||||
let mut src_raw_ptr = data.as_ptr() as usize;
|
||||
for dest_page in (addr..addr + size).step_by(PAGE_SIZE) {
|
||||
let ret = unsafe { do_eacceptcopy(&si as *const sec_info_t, dest_page, src_raw_ptr) };
|
||||
if ret != 0 {
|
||||
return_errno!(EFAULT, "do_eacceptcopy failure");
|
||||
}
|
||||
|
||||
Self::modify_permissions(dest_page, PAGE_SIZE, VMPerms::DEFAULT, perm)?;
|
||||
src_raw_ptr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// To replace sgx_mm_modify_permissions
|
||||
fn modify_permissions(
|
||||
addr: usize,
|
||||
length: usize,
|
||||
current_protection: VMPerms,
|
||||
new_protection: VMPerms,
|
||||
) -> Result<()> {
|
||||
if current_protection == new_protection {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let flags_from = current_protection.bits() | SGX_EMA_PAGE_TYPE_REG;
|
||||
let flags_to = new_protection.bits() | SGX_EMA_PAGE_TYPE_REG;
|
||||
let ret = unsafe { sgx_mm_modify_ocall(addr, length, flags_from as i32, flags_to as i32) };
|
||||
if ret != 0 {
|
||||
return_errno!(EFAULT, "sgx_mm_modify_ocall failure");
|
||||
}
|
||||
|
||||
let si = sec_info_t::new_for_modify_permission(&new_protection);
|
||||
for page in (addr..addr + length).step_by(PAGE_SIZE) {
|
||||
debug_assert!(page % PAGE_SIZE == 0);
|
||||
|
||||
if new_protection.bits() | current_protection.bits() != current_protection.bits() {
|
||||
unsafe { do_emodpe(&si as *const sec_info_t, page) };
|
||||
// Check this return value is useless. RAX is set to SE_EMODPE which is 6 defined in SDK.
|
||||
}
|
||||
// If new permission is RWX, no EMODPR needed in untrusted part, hence no EACCEPT
|
||||
if new_protection != VMPerms::ALL {
|
||||
let ret = unsafe { do_eaccept(&si, page) };
|
||||
if ret != 0 {
|
||||
return_errno!(EFAULT, "do_eaccept failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ???
|
||||
if new_protection == VMPerms::NONE {
|
||||
let ret = unsafe {
|
||||
sgx_mm_modify_ocall(
|
||||
addr,
|
||||
length,
|
||||
(SGX_EMA_PAGE_TYPE_REG | SGX_EMA_PROT_NONE) as i32,
|
||||
(SGX_EMA_PAGE_TYPE_REG | SGX_EMA_PROT_NONE) as i32,
|
||||
)
|
||||
};
|
||||
if ret != 0 {
|
||||
return_errno!(EFAULT, "sgx_mm_modify_ocall failure for permission None");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -778,7 +778,10 @@ impl InternalVMManager {
|
||||
let mut vma = new_chunk.get_vma_for_single_vma_chunk();
|
||||
// Reset memory permissions
|
||||
if !vma.perms().is_default() {
|
||||
vma.modify_permissions_for_committed_pages(VMPerms::default())
|
||||
vma.modify_permissions_for_committed_pages(
|
||||
vma.perms(),
|
||||
VMPerms::default(),
|
||||
)
|
||||
}
|
||||
// Reset memory contents
|
||||
unsafe {
|
||||
@ -926,7 +929,7 @@ impl InternalVMManager {
|
||||
(true, true) => {
|
||||
// Exact the same vma
|
||||
containing_vma.set_perms(new_perms);
|
||||
containing_vma.modify_permissions_for_committed_pages(new_perms);
|
||||
containing_vma.modify_permissions_for_committed_pages(old_perms, new_perms);
|
||||
return Ok(());
|
||||
}
|
||||
(false, false) => {
|
||||
@ -942,7 +945,8 @@ impl InternalVMManager {
|
||||
new_perms,
|
||||
VMAccess::Private(current_pid),
|
||||
);
|
||||
new_vma.modify_permissions_for_committed_pages(new_perms);
|
||||
new_vma
|
||||
.modify_permissions_for_committed_pages(containing_vma.perms(), new_perms);
|
||||
|
||||
let remaining_old_vma = {
|
||||
let range = VMRange::new(protect_range.end(), old_end).unwrap();
|
||||
@ -966,7 +970,8 @@ impl InternalVMManager {
|
||||
new_perms,
|
||||
VMAccess::Private(current_pid),
|
||||
);
|
||||
new_vma.modify_permissions_for_committed_pages(new_perms);
|
||||
new_vma
|
||||
.modify_permissions_for_committed_pages(containing_vma.perms(), new_perms);
|
||||
|
||||
if same_start {
|
||||
// Protect range is at left side of the containing vma
|
||||
|
Loading…
Reference in New Issue
Block a user