[libos] Add PKU support
This commit is contained in:
		
							parent
							
								
									46ccbd4ee4
								
							
						
					
					
						commit
						338dda643b
					
				| @ -173,6 +173,10 @@ enclave { | ||||
| 
 | ||||
|         int occlum_ocall_mprotect([user_check] void* addr, size_t len, int prot); | ||||
| 
 | ||||
|         int occlum_ocall_pkey_alloc(unsigned int flags, unsigned int access_rights); | ||||
|         int occlum_ocall_pkey_mprotect([user_check] void* addr, size_t len, int prot, int pkey); | ||||
|         int occlum_ocall_pkey_free(int pkey); | ||||
| 
 | ||||
|         int occlum_ocall_get_numa_topology( | ||||
|             [out, count=ncpus] uint32_t *numa_buf, | ||||
|             size_t ncpus | ||||
|  | ||||
| @ -43,6 +43,7 @@ sgx1_exception_sim = [] # Simulate #PF and #GP exceptions on SGX 1 | ||||
| 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 | ||||
| 
 | ||||
| [target.'cfg(not(target_env = "sgx"))'.dependencies] | ||||
| sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" } | ||||
|  | ||||
| @ -45,9 +45,12 @@ LIBOS_LOG ?= error | ||||
| 
 | ||||
| LIBOS_SONAME := libocclum-libos.so.$(MAJOR_VER_NUM) | ||||
| 
 | ||||
| LIBOS_FEATURES := | ||||
| 
 | ||||
| ifeq ($(SGX_MODE), HW) | ||||
| 	LIBOS_CORE_LIB_NAME := occlum-libos-core | ||||
| 	LIBOS_SO_REAL := $(BUILD_DIR)/lib/libocclum-libos.so.$(VERSION_NUM) | ||||
| 	LIBOS_FEATURES += pku | ||||
| else ifeq ($(SGX_MODE), HYPER) | ||||
| 	LIBOS_CORE_LIB_NAME := occlum-libos-core_hyper | ||||
| 	LIBOS_SO_REAL := $(BUILD_DIR)/lib/libocclum-libos_hyper.so.$(VERSION_NUM) | ||||
| @ -122,8 +125,6 @@ else | ||||
|     RUSTC_WRAPPER := | ||||
| endif | ||||
| 
 | ||||
| LIBOS_FEATURES := | ||||
| 
 | ||||
| ifndef OCCLUM_DISABLE_DCAP | ||||
|     LIBOS_FEATURES += dcap | ||||
| endif | ||||
|  | ||||
| @ -37,6 +37,9 @@ void do_exit_task(void); | ||||
| 
 | ||||
| #else  /* __ASSEMBLY__ */ | ||||
| 
 | ||||
| #define PKRU_LIBOS          (0x0) | ||||
| #define PKRU_USER           (0x55555551) | ||||
| 
 | ||||
| /* See /<path-to-linux-sgx>/common/inc/internal/thread_data.h */ | ||||
| #define TD_STACKGUARD_OFFSET        (8 * 5) | ||||
| /* Override the field for stack guard */ | ||||
|  | ||||
| @ -70,11 +70,19 @@ pub extern "C" fn occlum_ecall_init( | ||||
|         // Init the log infrastructure first so that log messages will be printed afterwards
 | ||||
|         util::log::init(log_level); | ||||
| 
 | ||||
|         // Init MPX for SFI if MPX is available
 | ||||
|         let report = rsgx_self_report(); | ||||
|         // Init MPX for SFI if MPX is available
 | ||||
|         if (report.body.attributes.xfrm & SGX_XFRM_MPX != 0) { | ||||
|             util::mpx_util::mpx_enable(); | ||||
|         } | ||||
|         // Init PKU for isolating LibOS form user-apps if PKU is available
 | ||||
|         // Occlum only turns on `pku` feature in HW mode
 | ||||
|         #[cfg(feature = "pku")] | ||||
|         { | ||||
|             if (report.body.attributes.xfrm & SGX_XFRM_PKRU != 0) { | ||||
|                 crate::util::pku_util::try_set_pku_enabled(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Register exception handlers (support cpuid & rdtsc for now)
 | ||||
|         register_exception_handlers(); | ||||
|  | ||||
| @ -14,6 +14,7 @@ use crate::fs::{ | ||||
| }; | ||||
| use crate::prelude::*; | ||||
| use crate::process::pgrp::{get_spawn_attribute_pgrp, update_pgrp_for_new_process}; | ||||
| use crate::util::pku_util; | ||||
| use crate::vm::ProcessVM; | ||||
| 
 | ||||
| mod aux_vec; | ||||
| @ -447,7 +448,11 @@ fn init_auxvec(process_vm: &ProcessVM, exec_elf_file: &ElfFile) -> Result<AuxVec | ||||
|     let ldso_elf_base = process_vm.get_elf_ranges()[1].start() as u64; | ||||
|     auxvec.set(AuxKey::AT_BASE, ldso_elf_base)?; | ||||
| 
 | ||||
|     let syscall_addr = __occlum_syscall_linux_abi as *const () as u64; | ||||
|     let syscall_addr = if pku_util::check_pku_enabled() { | ||||
|         __occlum_syscall_linux_pku_abi | ||||
|     } else { | ||||
|         __occlum_syscall_linux_abi | ||||
|     } as *const () as u64; | ||||
|     auxvec.set(AuxKey::AT_OCCLUM_ENTRY, syscall_addr)?; | ||||
|     // TODO: init AT_EXECFN
 | ||||
|     // auxvec.set_val(AuxKey::AT_EXECFN, "program_name")?;
 | ||||
| @ -457,5 +462,6 @@ fn init_auxvec(process_vm: &ProcessVM, exec_elf_file: &ElfFile) -> Result<AuxVec | ||||
| 
 | ||||
| extern "C" { | ||||
|     fn __occlum_syscall_linux_abi() -> i64; | ||||
|     fn __occlum_syscall_linux_pku_abi() -> i64; | ||||
|     fn occlum_gdb_hook_load_elf(elf_base: u64, elf_path: *const u8, elf_path_len: u64); | ||||
| } | ||||
|  | ||||
| @ -68,6 +68,20 @@ __exec_task: | ||||
| 
 | ||||
|     // Use user stack | ||||
|     movq TASK_USER_RSP(%rdi), %rsp | ||||
|     // Run user code | ||||
|     // Get user code address | ||||
|     movq TASK_USER_ENTRY_ADDR(%rdi), %r11 | ||||
| 
 | ||||
|     // Whether to switch PKRU value | ||||
|     mov pku_enabled(%rip), %r10 | ||||
|     cmp $1, %r10 | ||||
|     je update_pkru_in_exec_task | ||||
| 
 | ||||
|     // Run user code | ||||
|     jmp *%r11 | ||||
| 
 | ||||
| update_pkru_in_exec_task: | ||||
|     xor %ecx, %ecx | ||||
|     xor %edx, %edx | ||||
|     mov $PKRU_USER, %eax | ||||
|     wrpkru | ||||
|     jmp *%r11 | ||||
|  | ||||
| @ -3,6 +3,22 @@ | ||||
| 
 | ||||
| 
 | ||||
|     .file "syscall_entry_x86-64.S" | ||||
|     .global __occlum_syscall_linux_pku_abi
 | ||||
|     .type __occlum_syscall_linux_pku_abi, @function
 | ||||
| __occlum_syscall_linux_pku_abi: | ||||
|     pushq %rcx | ||||
|     pushq %rdx | ||||
|     pushq %rax | ||||
| 
 | ||||
|     xor %ecx, %ecx | ||||
|     xor %edx, %edx | ||||
|     mov $PKRU_LIBOS, %eax | ||||
|     wrpkru | ||||
| 
 | ||||
|     popq %rax | ||||
|     popq %rdx | ||||
|     popq %rcx | ||||
| 
 | ||||
|     .global __occlum_syscall_linux_abi
 | ||||
|     .type __occlum_syscall_linux_abi, @function
 | ||||
| __occlum_syscall_linux_abi: | ||||
| @ -128,7 +144,42 @@ __occlum_sysret: | ||||
|     pop %rax | ||||
|     pop %rcx | ||||
|     pop %rsp | ||||
| 
 | ||||
|     // Store RFLAGS since `cmp` operation may overwrite it | ||||
|     pushfq | ||||
|     push %rax | ||||
| 
 | ||||
|     mov pku_enabled(%rip), %rax | ||||
|     cmp $1, %rax | ||||
|     je update_pkru_in_sysret | ||||
| 
 | ||||
|     pop %rax | ||||
|     popfq | ||||
| 
 | ||||
|     jmp *%gs:(TD_SYSCALL_RET_ADDR_OFFSET) | ||||
|     // This should never happen | ||||
|     ud2 | ||||
| 
 | ||||
| update_pkru_in_sysret: | ||||
|     pop %rax | ||||
|     popfq | ||||
| 
 | ||||
|     sub $0x20, %rsp | ||||
|     mov %rax, (%rsp) | ||||
|     mov %rdx, 0x8(%rsp) | ||||
|     mov %rcx, 0x10(%rsp) | ||||
|     mov %gs:(TD_SYSCALL_RET_ADDR_OFFSET), %rcx | ||||
|     mov %rcx, 0x18(%rsp) | ||||
| 
 | ||||
|     xor %ecx, %ecx | ||||
|     xor %edx, %edx | ||||
|     mov $PKRU_USER, %eax | ||||
|     wrpkru | ||||
| 
 | ||||
|     pop %rax | ||||
|     pop %rdx | ||||
|     pop %rcx | ||||
|     ret | ||||
| 
 | ||||
|     .global __occlum_syscall_c_abi
 | ||||
|     .type __occlum_syscall_c_abi, @function
 | ||||
|  | ||||
| @ -6,5 +6,6 @@ pub mod hosts_parser_util; | ||||
| pub mod log; | ||||
| pub mod mem_util; | ||||
| pub mod mpx_util; | ||||
| pub mod pku_util; | ||||
| pub mod sgx; | ||||
| pub mod sync; | ||||
|  | ||||
							
								
								
									
										101
									
								
								src/libos/src/util/pku_util.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										101
									
								
								src/libos/src/util/pku_util.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| use std::sync::atomic::{AtomicBool, Ordering}; | ||||
| 
 | ||||
| /// Status variable accessed by assembly code
 | ||||
| #[no_mangle] | ||||
| pub static mut pku_enabled: u64 = 0; | ||||
| 
 | ||||
| lazy_static! { | ||||
|     pub static ref PKU_ENABLED: AtomicBool = AtomicBool::new(false); | ||||
| } | ||||
| 
 | ||||
| const PKEY_LIBOS: i32 = 0; | ||||
| const PKEY_USER: i32 = 1; | ||||
| 
 | ||||
| /// Try enable PKU features in Occlum.
 | ||||
| pub fn try_set_pku_enabled() { | ||||
|     // Alloc pkey
 | ||||
|     let mut pkey = -1; | ||||
|     let sgx_status = unsafe { occlum_ocall_pkey_alloc(&mut pkey, 0, 0) }; | ||||
|     assert!(sgx_status == sgx_status_t::SGX_SUCCESS && pkey == PKEY_USER); | ||||
| 
 | ||||
|     unsafe { | ||||
|         pku_enabled = 1; | ||||
|     } | ||||
|     assert!(PKU_ENABLED.load(Ordering::Relaxed) == false); | ||||
|     PKU_ENABLED.store(true, Ordering::Release); | ||||
| } | ||||
| 
 | ||||
| pub fn check_pku_enabled() -> bool { | ||||
|     PKU_ENABLED.load(Ordering::Acquire) | ||||
| } | ||||
| 
 | ||||
| pub fn pkey_mprotect_userspace_mem(user_mem_base: usize, user_mem_len: usize, perm: i32) { | ||||
|     if !self::check_pku_enabled() { | ||||
|         return; | ||||
|     } | ||||
|     let mut retval = -1; | ||||
|     debug!( | ||||
|         "associate memory region: 0x{:x} -> 0x{:x}, size: 0x{:x} with pkey for userspace: {:?}", | ||||
|         user_mem_base, | ||||
|         user_mem_base + user_mem_len, | ||||
|         user_mem_len, | ||||
|         PKEY_USER | ||||
|     ); | ||||
|     let sgx_status = unsafe { | ||||
|         occlum_ocall_pkey_mprotect( | ||||
|             &mut retval, | ||||
|             user_mem_base as *const c_void, | ||||
|             user_mem_len, | ||||
|             perm, | ||||
|             PKEY_USER, | ||||
|         ) | ||||
|     }; | ||||
|     assert!(sgx_status == sgx_status_t::SGX_SUCCESS && retval == 0); | ||||
| } | ||||
| 
 | ||||
| pub fn clear_pku_when_libos_exit(user_mem_base: usize, user_mem_len: usize, perm: i32) { | ||||
|     if !self::check_pku_enabled() { | ||||
|         return; | ||||
|     } | ||||
|     let mut retval = -1; | ||||
|     debug!( | ||||
|         "re-associate memory region  0x{:x} -> 0x{:x}, size: 0x{:x} with pkey for libos: {:?}", | ||||
|         user_mem_base, | ||||
|         user_mem_base + user_mem_len, | ||||
|         user_mem_len, | ||||
|         PKEY_LIBOS | ||||
|     ); | ||||
|     let sgx_status = unsafe { | ||||
|         occlum_ocall_pkey_mprotect( | ||||
|             &mut retval, | ||||
|             user_mem_base as *const c_void, | ||||
|             user_mem_len, | ||||
|             perm, | ||||
|             PKEY_LIBOS, | ||||
|         ) | ||||
|     }; | ||||
|     assert!(sgx_status == sgx_status_t::SGX_SUCCESS && retval == 0); | ||||
|     debug!("free pkey: {:?}", PKEY_USER); | ||||
|     let sgx_status = unsafe { occlum_ocall_pkey_free(&mut retval, PKEY_USER) }; | ||||
|     assert!(sgx_status == sgx_status_t::SGX_SUCCESS && retval == 0); | ||||
| } | ||||
| 
 | ||||
| extern "C" { | ||||
|     pub fn occlum_ocall_pkey_alloc( | ||||
|         retval: *mut i32, | ||||
|         flags: u32, | ||||
|         access_rights: u32, | ||||
|     ) -> sgx_status_t; | ||||
| 
 | ||||
|     pub fn occlum_ocall_pkey_mprotect( | ||||
|         retval: *mut i32, | ||||
|         addr: *const c_void, | ||||
|         len: usize, | ||||
|         prot: i32, | ||||
|         pkey: i32, | ||||
|     ) -> sgx_status_t; | ||||
| 
 | ||||
|     pub fn occlum_ocall_pkey_free(retval: *mut i32, pkey: i32) -> sgx_status_t; | ||||
| } | ||||
| @ -1,10 +1,14 @@ | ||||
| use super::ipc::SHM_MANAGER; | ||||
| use super::*; | ||||
| use crate::ctor::dtor; | ||||
| use crate::util::pku_util; | ||||
| use config::LIBOS_CONFIG; | ||||
| use std::ops::{Deref, DerefMut}; | ||||
| use vm_manager::VMManager; | ||||
| 
 | ||||
| const RSRV_MEM_PERM: MemPerm = | ||||
|     MemPerm::from_bits_truncate(MemPerm::READ.bits() | MemPerm::WRITE.bits()); | ||||
| 
 | ||||
| /// The virtual memory manager for the entire user space
 | ||||
| pub struct UserSpaceVMManager(VMManager); | ||||
| 
 | ||||
| @ -16,13 +20,13 @@ impl UserSpaceVMManager { | ||||
|             // a lot of time. When EDMM is supported, there is no need to commit all the pages at the initialization stage. A function
 | ||||
|             // which reserves memory but not commit pages should be provided then.
 | ||||
|             let ptr = sgx_alloc_rsrv_mem(rsrv_mem_size); | ||||
|             let perm = MemPerm::READ | MemPerm::WRITE; | ||||
|             if ptr.is_null() { | ||||
|                 return_errno!(ENOMEM, "run out of reserved memory"); | ||||
|             } | ||||
|             // Change the page permission to RW (default)
 | ||||
|             assert!( | ||||
|                 sgx_tprotect_rsrv_mem(ptr, rsrv_mem_size, perm.bits()) == sgx_status_t::SGX_SUCCESS | ||||
|                 sgx_tprotect_rsrv_mem(ptr, rsrv_mem_size, RSRV_MEM_PERM.bits()) | ||||
|                     == sgx_status_t::SGX_SUCCESS | ||||
|             ); | ||||
| 
 | ||||
|             let addr = ptr as usize; | ||||
| @ -30,6 +34,7 @@ impl UserSpaceVMManager { | ||||
|                 "allocated rsrv addr is 0x{:x}, len is 0x{:x}", | ||||
|                 addr, rsrv_mem_size | ||||
|             ); | ||||
|             pku_util::pkey_mprotect_userspace_mem(addr, rsrv_mem_size, RSRV_MEM_PERM.bits()); | ||||
|             VMRange::new(addr, addr + rsrv_mem_size)? | ||||
|         }; | ||||
| 
 | ||||
| @ -50,10 +55,11 @@ fn free_user_space() { | ||||
|     SHM_MANAGER.clean_when_libos_exit(); | ||||
|     let range = USER_SPACE_VM_MANAGER.range(); | ||||
|     assert!(USER_SPACE_VM_MANAGER.verified_clean_when_exit()); | ||||
|     let addr = range.start() as *const c_void; | ||||
|     let addr = range.start(); | ||||
|     let size = range.size(); | ||||
|     info!("free user space VM: {:?}", range); | ||||
|     assert!(unsafe { sgx_free_rsrv_mem(addr, size) == 0 }); | ||||
|     pku_util::clear_pku_when_libos_exit(addr, size, RSRV_MEM_PERM.bits()); | ||||
|     assert!(unsafe { sgx_free_rsrv_mem(addr as *const c_void, size) == 0 }); | ||||
| } | ||||
| 
 | ||||
| impl Deref for UserSpaceVMManager { | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| #define _GNU_SOURCE | ||||
| #include <stdlib.h> | ||||
| #include <sys/mman.h> | ||||
| #include "ocalls.h" | ||||
| @ -30,3 +31,15 @@ void occlum_ocall_free(void *ptr) { | ||||
| int occlum_ocall_mprotect(void *addr, size_t len, int prot) { | ||||
|     return mprotect(addr, len, prot); | ||||
| } | ||||
| 
 | ||||
| int occlum_ocall_pkey_alloc(unsigned int flags, unsigned int access_rights) { | ||||
|     return pkey_alloc(flags, access_rights); | ||||
| } | ||||
| 
 | ||||
| int occlum_ocall_pkey_mprotect(void *addr, size_t len, int prot, int pkey) { | ||||
|     return pkey_mprotect(addr, len, prot, pkey); | ||||
| } | ||||
| 
 | ||||
| int occlum_ocall_pkey_free(int pkey) { | ||||
|     return pkey_free(pkey); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user