Refactor Occlum PAL as a shared library

By providing Occlum PAL as a shared library, it is now possible to embed and
use Occlum in an user-controled process (instead of an Occlum-controlled one).

The APIs of Occlum PAL can be found in `src/pal/include/occlum_pal_api.h`. The
Occlum PAL library, namely `libocclum-pal.so`, can be found in `.occlum/build/lib`.
To use the library, check out the source code of `occlum-run` (under
`src/run`), which can be seen as a sample code for using the Occlum PAL
library.
This commit is contained in:
Tate, Hongliang Tian 2019-12-18 08:27:54 +00:00
parent 61cf75e68b
commit a84803e951
44 changed files with 914 additions and 721 deletions

@ -33,6 +33,8 @@ install:
install -t $(OCCLUM_PREFIX)/src/libos/ -m 444 src/libos/Makefile src/libos/Enclave.lds
install -d $(OCCLUM_PREFIX)/src/libos/src/builtin/
install -t $(OCCLUM_PREFIX)/src/libos/src/builtin/ -m 444 src/libos/src/builtin/*
install -d $(OCCLUM_PREFIX)/include/
install -t $(OCCLUM_PREFIX)/include/ -m 444 src/pal/include/*
install -d $(OCCLUM_PREFIX)/etc/template/
install -t $(OCCLUM_PREFIX)/etc/template/ -m 444 etc/template/*

@ -9,28 +9,61 @@ enclave {
include "sgx_quote.h"
trusted {
/* define ECALLs here. */
public int libos_boot([in, string] const char* executable_path, [user_check] const char** argv);
public int libos_run(int host_tid);
/* This is only for debug usage */
public int dummy_ecall(void);
/*
* Create a new LibOS process to do the task specified by the given
* arguments.
*
* @retval On success, return the thread ID of the
* newly-created process (pid == tid for a new process). On error,
* return -1. The user can check errno for the concrete error type.
*/
public int occlum_ecall_new_process(
[in, string] const char* executable_path,
[user_check] const char** argv);
/*
* Execute the LibOS thread specified by the TID.
*
* This API is synchronous: it returns until the LibOS thread exits.
*
* @retval On success, return the exit status of the thread. On error,
* return -1. The user can check errno for the concrete error type.
*/
public int occlum_ecall_exec_thread(int libos_tid, int host_tid);
/*
* A do-nothing ECall for debug purpose only.
*/
public void occlum_ecall_nop(void);
};
untrusted {
void ocall_print_string([in, string] const char* msg);
int ocall_run_new_task(void);
void ocall_gettimeofday([out] long* sec, [out] long* us);
void ocall_clock_gettime(int clockid, [out] long* sec, [out] long* ns);
void ocall_nanosleep(long sec, long nsec);
void ocall_sync(void);
void ocall_sched_yield(void);
int ocall_sched_getaffinity([out] int *error, int pid, size_t cpusize, [out, size=cpusize] unsigned char* buf);
int ocall_sched_setaffinity([out] int *error, int pid, size_t cpusize, [in, size=cpusize] const unsigned char* buf);
/*
* Execute the LibOS thread specified by a TID in a new host OS thread.
*
* This API is asynchronous: it immediately returns after successfully
* creating a new host OS thread that will enter the enclave and execute the
* the LibOS thread (using occlum_ecall_exec_process).
*
* @retval On success, return 0. On error, return -1.
*/
int occlum_ocall_exec_thread_async(int libos_tid);
sgx_status_t ocall_sgx_init_quote(
[out] sgx_target_info_t *target_info,
[out] sgx_epid_group_id_t *epid_group_id);
sgx_status_t ocall_sgx_get_quote(
void occlum_ocall_gettimeofday([out] long* sec, [out] long* us);
void occlum_ocall_clock_gettime(int clockid, [out] long* sec, [out] long* ns);
void occlum_ocall_nanosleep(long sec, long nsec);
void occlum_ocall_sync(void);
void occlum_ocall_sched_yield(void);
int occlum_ocall_sched_getaffinity([out] int *error, int pid, size_t cpusize, [out, size=cpusize] unsigned char* buf);
int occlum_ocall_sched_setaffinity([out] int *error, int pid, size_t cpusize, [in, size=cpusize] const unsigned char* buf);
sgx_status_t occlum_ocall_sgx_init_quote(
[out] sgx_target_info_t* target_info,
[out] sgx_epid_group_id_t* epid_group_id);
sgx_status_t occlum_ocall_sgx_get_quote(
[in, size=sigrl_len] uint8_t* sigrl,
uint32_t sigrl_len,
[in] sgx_report_t* report,
@ -38,10 +71,10 @@ enclave {
[in] sgx_spid_t* spid,
[in] sgx_quote_nonce_t* nonce,
[out] sgx_report_t* qe_report,
[out, size=quote_buf_len] uint8_t* quote_buf,
[out, size=quote_buf_len] sgx_quote_t* quote_buf,
uint32_t quote_buf_len);
int64_t ocall_sendmsg(
int64_t occlum_ocall_sendmsg(
int sockfd,
[in, size=msg_namelen] const void* msg_name,
socklen_t msg_namelen,
@ -51,8 +84,7 @@ enclave {
size_t msg_controllen,
int flags
) propagate_errno;
int64_t ocall_recvmsg(
int64_t occlum_ocall_recvmsg(
int sockfd,
[out, size=msg_namelen] void *msg_name,
socklen_t msg_namelen,

@ -3,7 +3,9 @@
all:
@$(MAKE) --no-print-directory -C libos
@$(MAKE) --no-print-directory -C pal
@$(MAKE) --no-print-directory -C run
clean:
@$(MAKE) --no-print-directory -C libos clean
@$(MAKE) --no-print-directory -C pal clean
@$(MAKE) --no-print-directory -C run clean

@ -3,7 +3,7 @@ name = "Occlum"
version = "0.8.0"
[lib]
name = "occlum_rs"
name = "occlum_libos_core_rs"
crate-type = ["staticlib"]
[dependencies]

@ -1,5 +1,38 @@
include ../sgxenv.mk
# An overview of the build process
#
# The target library:
# libocclum-libos.so
#
# The intermediate libraries:
# libocclum-libos-core.a
# libocclum_libos_core_rs.a
#
# Diagram:
#
# +-------------------+
# |LibOS (Enclave)<--------+ libocclum-libos.so
# | +---------------| |
# | |LibOS Core <----------+ libocclum-libos-core.a
# | | +----------| | |
# | | |Rust <-------------+ libocclum_libos_core_rs.a
# | | +----------+ | | (Rust forbids the use of hypens in library names)
# | | |C | | |
# | | +----------+ | |
# | | |Assembly | | |
# | | +----------+ | |
# | +---------------+ |
# | |LibOS Builtins<-------+ Configurable by Occlum.json
# | +---------------+ |
# | |
# | +---------------+ |
# | |Rust SGX SDK <-----+
# | +---------------| | +--+ Dependencies
# | |Intel SGX SDK<-----+
# | +---------------| |
# +-------------------+
# Build LibOS in debug or release mode
LIBOS_RELEASE ?= 0
@ -19,13 +52,9 @@ LIBOS_LOG ?= error
ONLY_REBUILD_BUILTIN ?= 0
# The final and intermediate libraries
#
# The relationships between the three Occlum libraries
# $(LIBOS_SO) > $(LIBOS_CORE_A) > $(LIBOS_RS_A)
LIBOS_SO := $(BUILD_DIR)/lib/libocclum.so
LIBOS_CORE_A := $(BUILD_DIR)/lib/libocclum_core.a
LIBOS_RS_A := $(BUILD_DIR)/lib/libocclum_rs.a
LIBOS_SO := $(BUILD_DIR)/lib/libocclum-libos.so
LIBOS_CORE_A := $(BUILD_DIR)/lib/libocclum-libos-core.a
LIBOS_CORE_RS_A := $(BUILD_DIR)/lib/libocclum_libos_core_rs.a
# The dependent libraries
LIBCOMPILER_RT_PATCH_A := $(BUILD_DIR)/lib/libcompiler-rt-patch.a
@ -62,7 +91,7 @@ C_FLAGS += -DOCCLUM_BUILTIN_VM_USER_SPACE_SIZE='($(OCCLUM_BUILTIN_VM_USER_SPACE_
endif
_Other_Link_Flags := -L$(RUST_SGX_SDK_DIR)/compiler-rt/ -L$(BUILD_DIR)/lib
_Other_Enclave_Libs := -lcompiler-rt-patch -locclum_core -lsgx_tprotected_fs
_Other_Enclave_Libs := -lcompiler-rt-patch -locclum-libos-core -lsgx_tprotected_fs
LINK_FLAGS := $(SGX_LFLAGS_T)
.PHONY: all clean
@ -83,17 +112,17 @@ $(LIBOS_SO): $(BUILTIN_C_OBJS)
@echo "LINK => $@"
endif
$(LIBOS_CORE_A): $(LIBOS_RS_A) $(C_OBJS) $(CXX_OBJS) $(S_OBJS) $(EDL_C_OBJS)
@cp $(LIBOS_RS_A) $(LIBOS_CORE_A)
$(LIBOS_CORE_A): $(LIBOS_CORE_RS_A) $(C_OBJS) $(CXX_OBJS) $(S_OBJS) $(EDL_C_OBJS)
@cp $(LIBOS_CORE_RS_A) $(LIBOS_CORE_A)
@ar r $@ $(C_OBJS) $(CXX_OBJS) $(S_OBJS) $(EDL_C_OBJS)
@echo "GEN => $@"
ifeq ($(LIBOS_RELEASE), 0)
$(LIBOS_RS_A): $(RUST_SRCS)
$(LIBOS_CORE_RS_A): $(RUST_SRCS)
@RUSTC_BOOTSTRAP=1 cargo build --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR)
@echo "CARGO (debug) => $@"
else
$(LIBOS_RS_A): $(RUST_SRCS)
$(LIBOS_CORE_RS_A): $(RUST_SRCS)
@RUSTC_BOOTSTRAP=1 cargo build --release --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR)
@echo "CARGO (release) => $@"
endif
@ -127,6 +156,6 @@ clean-builtin:
@-$(RM) -f $(BUILTIN_C_OBJS)
clean: clean-builtin
@-$(RM) -f $(LIBOS_SO) $(LIBOS_CORE_A) $(LIBOS_RS_A) \
@-$(RM) -f $(LIBOS_SO) $(LIBOS_CORE_A) $(LIBOS_CORE_RS_A) \
$(LIBCOMPILER_RT_PATCH_A) $(EDL_C_OBJS) $(EDL_C_SRCS) $(C_OBJS) $(CXX_OBJS) $(S_OBJS)
@-$(RM) -rf $(RUST_TARGET_DIR)

@ -7,7 +7,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
use util::mem_util::from_untrusted::*;
const ENCLAVE_PATH: &'static str = ".occlum/build/lib/libocclum.signed.so";
const ENCLAVE_PATH: &'static str = ".occlum/build/lib/libocclum-libos.signed.so";
lazy_static! {
static ref INIT_ONCE: Once = Once::new();
@ -15,7 +15,10 @@ lazy_static! {
}
#[no_mangle]
pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char) -> i32 {
pub extern "C" fn occlum_ecall_new_process(
path_buf: *const c_char,
argv: *const *const c_char,
) -> i32 {
INIT_ONCE.call_once(|| {
// Init the log infrastructure first so that log messages will be printed afterwards
util::log::init();
@ -37,8 +40,8 @@ pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char
// register exception handlers (support cpuid & rdtsc for now)
let _ = backtrace::enable_backtrace(ENCLAVE_PATH, PrintFormat::Short);
panic::catch_unwind(|| {
backtrace::__rust_begin_short_backtrace(|| match do_boot(&path, &args) {
Ok(()) => 0,
backtrace::__rust_begin_short_backtrace(|| match do_new_process(&path, &args) {
Ok(pid_t) => pid_t as i32,
Err(e) => {
error!("failed to boot up LibOS: {}", e.backtrace());
EXIT_STATUS_INTERNAL_ERROR
@ -49,28 +52,28 @@ pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char
}
#[no_mangle]
pub extern "C" fn libos_run(host_tid: i32) -> i32 {
pub extern "C" fn occlum_ecall_exec_thread(libos_pid: i32, host_tid: i32) -> i32 {
if ALLOW_RUN.load(Ordering::SeqCst) == false {
return EXIT_STATUS_INTERNAL_ERROR;
}
let _ = backtrace::enable_backtrace(ENCLAVE_PATH, PrintFormat::Short);
panic::catch_unwind(|| {
backtrace::__rust_begin_short_backtrace(|| match do_run(host_tid as pid_t) {
backtrace::__rust_begin_short_backtrace(|| {
match do_exec_thread(libos_pid as pid_t, host_tid as pid_t) {
Ok(exit_status) => exit_status,
Err(e) => {
error!("failed to execute a process: {}", e.backtrace());
EXIT_STATUS_INTERNAL_ERROR
}
}
})
})
.unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
}
#[no_mangle]
pub extern "C" fn dummy_ecall() -> i32 {
0
}
pub extern "C" fn occlum_ecall_nop() {}
// Use -128 as a special value to indicate internal error from libos, not from
// user programs. The LibOS ensures that an user program can only return a
@ -103,19 +106,20 @@ fn parse_arguments(
Ok((path_buf, args))
}
fn do_boot(program_path: &PathBuf, argv: &Vec<CString>) -> Result<()> {
fn do_new_process(program_path: &PathBuf, argv: &Vec<CString>) -> Result<pid_t> {
validate_program_path(program_path)?;
let envp = &config::LIBOS_CONFIG.env;
let file_actions = Vec::new();
let parent = &process::IDLE_PROCESS;
let program_path_str = program_path.to_str().unwrap();
process::do_spawn(&program_path_str, argv, envp, &file_actions, parent)?;
Ok(())
let new_tid =
process::do_spawn_without_exec(&program_path_str, argv, envp, &file_actions, parent)?;
Ok(new_tid)
}
fn do_run(host_tid: pid_t) -> Result<i32> {
let exit_status = process::run_task(host_tid)?;
fn do_exec_thread(libos_tid: pid_t, host_tid: pid_t) -> Result<i32> {
let exit_status = process::run_task(libos_tid, host_tid)?;
// sync file system
// TODO: only sync when all processes exit

@ -56,7 +56,7 @@ impl InnerAgent {
fn init_fields() -> Result<(sgx_target_info_t, sgx_epid_group_id_t)> {
extern "C" {
pub fn ocall_sgx_init_quote(
pub fn occlum_ocall_sgx_init_quote(
retval: *mut sgx_status_t,
target_info: *mut sgx_target_info_t,
epid_group_id: *mut sgx_epid_group_id_t,
@ -67,7 +67,7 @@ impl InnerAgent {
let mut epid_group_id = Default::default();
unsafe {
let mut retval = Default::default();
let status = ocall_sgx_init_quote(
let status = occlum_ocall_sgx_init_quote(
&mut retval as *mut sgx_status_t,
&mut target_info as *mut sgx_target_info_t,
&mut epid_group_id as *mut sgx_epid_group_id_t,
@ -75,7 +75,7 @@ impl InnerAgent {
assert!(status == sgx_status_t::SGX_SUCCESS);
if (retval != sgx_status_t::SGX_SUCCESS) {
return_errno!(EINVAL, "ocall_sgx_init_quote failed");
return_errno!(EINVAL, "occlum_ocall_sgx_init_quote failed");
}
}
@ -95,7 +95,7 @@ impl InnerAgent {
nonce: &sgx_quote_nonce_t,
) -> Result<SgxQuote> {
extern "C" {
pub fn ocall_sgx_get_quote(
pub fn occlum_ocall_sgx_get_quote(
retval: *mut sgx_status_t, // Output
sigrl: *const u8, // Input (optional)
sigrl_len: u32, // Input (optional)
@ -137,7 +137,7 @@ impl InnerAgent {
// Do OCall
unsafe {
let mut retval = Default::default();
let status = ocall_sgx_get_quote(
let status = occlum_ocall_sgx_get_quote(
&mut retval as *mut sgx_status_t,
sigrl_ptr,
sigrl_size,
@ -154,9 +154,9 @@ impl InnerAgent {
if retval != sgx_status_t::SGX_SUCCESS {
match retval {
sgx_status_t::SGX_ERROR_BUSY => {
return_errno!(EBUSY, "ocall_sgx_get_quote is temporarily busy")
return_errno!(EBUSY, "occlum_ocall_sgx_get_quote is temporarily busy")
}
_ => return_errno!(EINVAL, "ocall_sgx_get_quote failed"),
_ => return_errno!(EINVAL, "occlum_ocall_sgx_get_quote failed"),
}
}
}

@ -436,7 +436,7 @@ pub fn do_sendfile(
}
extern "C" {
fn ocall_sync() -> sgx_status_t;
fn occlum_ocall_sync() -> sgx_status_t;
}
impl Process {

@ -1,5 +1,5 @@
#![allow(unused)]
#![crate_name = "occlum_rs"]
#![crate_name = "occlum_libos_core_rs"]
#![crate_type = "staticlib"]
#![cfg_attr(not(target_env = "sgx"), no_std)]
#![cfg_attr(target_env = "sgx", feature(rustc_private))]

@ -75,7 +75,7 @@ impl SocketFile {
// Do OCall
let retval = try_libc!({
let mut retval = 0_isize;
let status = ocall_recvmsg(
let status = occlum_ocall_recvmsg(
&mut retval as *mut isize,
host_fd,
msg_name,
@ -121,7 +121,7 @@ impl SocketFile {
}
extern "C" {
fn ocall_recvmsg(
fn occlum_ocall_recvmsg(
ret: *mut ssize_t,
fd: c_int,
msg_name: *mut c_void,

@ -49,7 +49,7 @@ impl SocketFile {
let flags = flags.to_u32() as i32;
// Do OCall
let status = ocall_sendmsg(
let status = occlum_ocall_sendmsg(
&mut retval as *mut isize,
host_fd,
msg_name,
@ -70,7 +70,7 @@ impl SocketFile {
}
extern "C" {
fn ocall_sendmsg(
fn occlum_ocall_sendmsg(
ret: *mut ssize_t,
fd: c_int,
msg_name: *const c_void,

@ -6,7 +6,7 @@ pub use self::futex::{
pub use self::process::{Status, IDLE_PROCESS};
pub use self::process_table::get;
pub use self::sched::{do_sched_getaffinity, do_sched_setaffinity, do_sched_yield, CpuSet};
pub use self::spawn::{do_spawn, ElfFile, FileAction, ProgramHeaderExt};
pub use self::spawn::{do_spawn, do_spawn_without_exec, ElfFile, FileAction, ProgramHeaderExt};
pub use self::task::{current_pid, get_current, run_task};
pub use self::thread::{do_clone, do_set_tid_address, CloneFlags, ThreadGroup};
pub use self::wait::{WaitQueue, Waiter};

@ -1,21 +1,21 @@
use super::*;
extern "C" {
fn ocall_sched_getaffinity(
fn occlum_ocall_sched_getaffinity(
ret: *mut i32,
errno: *mut i32,
pid: i32,
cpusetsize: size_t,
mask: *mut c_uchar,
) -> sgx_status_t;
fn ocall_sched_setaffinity(
fn occlum_ocall_sched_setaffinity(
ret: *mut i32,
errno: *mut i32,
pid: i32,
cpusetsize: size_t,
mask: *const c_uchar,
) -> sgx_status_t;
fn ocall_sched_yield() -> sgx_status_t;
fn occlum_ocall_sched_yield() -> sgx_status_t;
}
pub struct CpuSet {
@ -96,11 +96,11 @@ pub fn do_sched_getaffinity(pid: pid_t, cpu_set: &mut CpuSet) -> Result<i32> {
let mut ret = 0;
let mut error = 0;
unsafe {
ocall_sched_getaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
occlum_ocall_sched_getaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
}
if (ret < 0) {
let errno = Errno::from(error as u32);
return_errno!(errno, "ocall_sched_getaffinity failed");
return_errno!(errno, "occlum_ocall_sched_getaffinity failed");
}
Ok(ret)
}
@ -115,18 +115,18 @@ pub fn do_sched_setaffinity(pid: pid_t, cpu_set: &CpuSet) -> Result<i32> {
let mut ret = 0;
let mut error = 0;
unsafe {
ocall_sched_setaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
occlum_ocall_sched_setaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
}
if (ret < 0) {
let errno = Errno::from(error as u32);
return_errno!(errno, "ocall_sched_setaffinity failed");
return_errno!(errno, "occlum_ocall_sched_setaffinity failed");
}
Ok(ret)
}
pub fn do_sched_yield() {
unsafe {
let status = ocall_sched_yield();
let status = occlum_ocall_sched_yield();
assert!(status == sgx_status_t::SGX_SUCCESS);
}
}

@ -17,27 +17,37 @@ mod elf_file;
mod init_stack;
mod init_vm;
#[derive(Debug)]
pub enum FileAction {
/// open(path, oflag, mode) had been called, and the returned file
/// descriptor, if not `fd`, had been changed to `fd`.
Open {
path: String,
mode: u32,
oflag: u32,
fd: FileDesc,
},
Dup2(FileDesc, FileDesc),
Close(FileDesc),
}
pub fn do_spawn(
elf_path: &str,
argv: &[CString],
envp: &[CString],
file_actions: &[FileAction],
parent_ref: &ProcessRef,
) -> Result<u32> {
) -> Result<pid_t> {
let (new_tid, new_process_ref) = new_process(elf_path, argv, envp, file_actions, parent_ref)?;
task::enqueue_and_exec_task(new_tid, new_process_ref);
Ok(new_tid)
}
pub fn do_spawn_without_exec(
elf_path: &str,
argv: &[CString],
envp: &[CString],
file_actions: &[FileAction],
parent_ref: &ProcessRef,
) -> Result<pid_t> {
let (new_tid, new_process_ref) = new_process(elf_path, argv, envp, file_actions, parent_ref)?;
task::enqueue_task(new_tid, new_process_ref);
Ok(new_tid)
}
fn new_process(
elf_path: &str,
argv: &[CString],
envp: &[CString],
file_actions: &[FileAction],
parent_ref: &ProcessRef,
) -> Result<(pid_t, ProcessRef)> {
let elf_buf = load_elf_to_vec(elf_path, parent_ref)
.cause_err(|e| errno!(e.errno(), "cannot load the executable"))?;
let ldso_path = "/lib/ld-musl-x86_64.so.1";
@ -86,8 +96,22 @@ pub fn do_spawn(
};
parent_adopts_new_child(&parent_ref, &new_process_ref);
process_table::put(new_pid, new_process_ref.clone());
task::enqueue_task(new_process_ref);
Ok(new_pid)
let new_tid = new_pid;
Ok((new_tid, new_process_ref))
}
#[derive(Debug)]
pub enum FileAction {
/// open(path, oflag, mode) had been called, and the returned file
/// descriptor, if not `fd`, had been changed to `fd`.
Open {
path: String,
mode: u32,
oflag: u32,
fd: FileDesc,
},
Dup2(FileDesc, FileDesc),
Close(FileDesc),
}
fn load_elf_to_vec(elf_path: &str, parent_ref: &ProcessRef) -> Result<Vec<u8>> {

@ -53,27 +53,39 @@ impl Task {
}
lazy_static! {
static ref NEW_PROCESS_QUEUE: SgxMutex<VecDeque<ProcessRef>> =
{ SgxMutex::new(VecDeque::new()) };
static ref NEW_PROCESS_TABLE: SgxMutex<HashMap<pid_t, ProcessRef>> =
{ SgxMutex::new(HashMap::new()) };
}
pub fn enqueue_task(new_process: ProcessRef) {
NEW_PROCESS_QUEUE.lock().unwrap().push_back(new_process);
pub fn enqueue_task(new_tid: pid_t, new_process: ProcessRef) {
let existing_task = NEW_PROCESS_TABLE
.lock()
.unwrap()
.insert(new_tid, new_process);
// There should NOT have any pending process with the same ID
assert!(existing_task.is_none());
}
pub fn enqueue_and_exec_task(new_tid: pid_t, new_process: ProcessRef) {
enqueue_task(new_tid, new_process);
let mut ret = 0;
let ocall_status = unsafe { ocall_run_new_task(&mut ret) };
let ocall_status = unsafe { occlum_ocall_exec_thread_async(&mut ret, new_tid) };
if ocall_status != sgx_status_t::SGX_SUCCESS || ret != 0 {
panic!("Failed to start the process");
}
}
fn dequeue_task() -> Option<ProcessRef> {
NEW_PROCESS_QUEUE.lock().unwrap().pop_front()
fn dequeue_task(libos_tid: pid_t) -> Result<ProcessRef> {
NEW_PROCESS_TABLE
.lock()
.unwrap()
.remove(&libos_tid)
.ok_or_else(|| errno!(EAGAIN, "the given TID does not match any pending process"))
}
pub fn run_task(host_tid: pid_t) -> Result<i32> {
let new_process: ProcessRef =
dequeue_task().ok_or_else(|| errno!(EAGAIN, "no new processes to run"))?;
pub fn run_task(libos_tid: pid_t, host_tid: pid_t) -> Result<i32> {
let new_process: ProcessRef = dequeue_task(libos_tid)?;
set_current(&new_process);
let (pid, task) = {
@ -148,6 +160,6 @@ fn reset_current() {
}
extern "C" {
fn ocall_run_new_task(ret: *mut i32) -> sgx_status_t;
fn occlum_ocall_exec_thread_async(ret: *mut i32, libos_tid: pid_t) -> sgx_status_t;
fn do_run_task(task: *mut Task) -> i32;
}

@ -106,7 +106,7 @@ pub fn do_clone(
}
}
task::enqueue_task(new_thread_ref);
task::enqueue_and_exec_task(new_thread_pid, new_thread_ref);
Ok(new_thread_pid)
}

@ -26,13 +26,13 @@ impl timeval_t {
pub fn do_gettimeofday() -> timeval_t {
let mut tv: timeval_t = Default::default();
unsafe {
ocall_gettimeofday(&mut tv.sec as *mut time_t, &mut tv.usec as *mut suseconds_t);
occlum_ocall_gettimeofday(&mut tv.sec as *mut time_t, &mut tv.usec as *mut suseconds_t);
}
tv
}
extern "C" {
fn ocall_gettimeofday(sec: *mut time_t, usec: *mut suseconds_t) -> sgx_status_t;
fn occlum_ocall_gettimeofday(sec: *mut time_t, usec: *mut suseconds_t) -> sgx_status_t;
}
#[repr(C)]
@ -88,13 +88,17 @@ impl ClockID {
pub fn do_clock_gettime(clockid: ClockID) -> Result<timespec_t> {
extern "C" {
fn ocall_clock_gettime(clockid: clockid_t, sec: *mut time_t, ns: *mut i64) -> sgx_status_t;
fn occlum_ocall_clock_gettime(
clockid: clockid_t,
sec: *mut time_t,
ns: *mut i64,
) -> sgx_status_t;
}
let mut sec = 0;
let mut nsec = 0;
unsafe {
ocall_clock_gettime(
occlum_ocall_clock_gettime(
clockid as clockid_t,
&mut sec as *mut time_t,
&mut nsec as *mut i64,
@ -105,10 +109,10 @@ pub fn do_clock_gettime(clockid: ClockID) -> Result<timespec_t> {
pub fn do_nanosleep(req: &timespec_t) -> Result<()> {
extern "C" {
fn ocall_nanosleep(sec: time_t, nsec: i64) -> sgx_status_t;
fn occlum_ocall_nanosleep(sec: time_t, nsec: i64) -> sgx_status_t;
}
unsafe {
ocall_nanosleep(req.sec, req.nsec);
occlum_ocall_nanosleep(req.sec, req.nsec);
}
Ok(())
}

@ -1,41 +1,42 @@
include ../sgxenv.mk
BIN := $(BUILD_DIR)/bin/occlum-pal
LIBOCCLUM_PAL_SO := $(BUILD_DIR)/lib/libocclum-pal.so
# A dependency on Rust SGX SDK
LIBSGX_USTDC_A := $(BUILD_DIR)/lib/libsgx_ustdc.a
EDL_C_SRCS := $(addprefix $(BUILD_DIR)/src/pal/,Enclave_u.c Enclave_u.h)
EDL_C_OBJS := $(addprefix $(BUILD_DIR)/src/pal/,Enclave_u.o)
C_SRCS := $(sort $(wildcard *.c */*.c))
EDL_C_SRCS := $(addprefix $(BUILD_DIR)/src/pal/src/,Enclave_u.c Enclave_u.h)
EDL_C_OBJS := $(addprefix $(BUILD_DIR)/src/pal/src/,Enclave_u.o)
C_SRCS := $(sort $(wildcard src/*.c src/*/*.c))
C_OBJS := $(addprefix $(BUILD_DIR)/src/pal/,$(C_SRCS:.c=.o))
CXX_SRCS := $(sort $(wildcard *.cpp */*.cpp))
CXX_SRCS := $(sort $(wildcard src/*.cpp src/*/*.cpp))
CXX_OBJS := $(addprefix $(BUILD_DIR)/src/pal/,$(CXX_SRCS:.cpp=.o))
C_COMMON_FLAGS := -I$(BUILD_DIR)/src/pal -Wno-unused-result
C_COMMON_FLAGS := -I$(BUILD_DIR)/src/pal/src -Iinclude
C_FLAGS := $(C_COMMON_FLAGS) $(SGX_CFLAGS_U)
CXX_FLAGS := $(C_COMMON_FLAGS) $(SGX_CXXFLAGS_U)
LINK_FLAGS := $(SGX_LFLAGS_U) -L$(RUST_SGX_SDK_DIR)/sgx_ustdc/ -lsgx_ustdc -lsgx_uprotected_fs
LINK_FLAGS := $(SGX_LFLAGS_U) -shared -L$(RUST_SGX_SDK_DIR)/sgx_ustdc/ -lsgx_ustdc -lsgx_uprotected_fs
LINK_FLAGS += -Wl,--version-script=pal.lds
ALL_BUILD_SUBDIRS := $(sort $(patsubst %/,%,$(dir $(BIN) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS))))
ALL_BUILD_SUBDIRS := $(sort $(patsubst %/,%,$(dir $(LIBOCCLUM_PAL_SO) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS))))
.PHONY: all clean
all: $(ALL_BUILD_SUBDIRS) $(BIN)
all: $(ALL_BUILD_SUBDIRS) $(LIBOCCLUM_PAL_SO)
$(ALL_BUILD_SUBDIRS):
@mkdir -p $@
$(BIN): $(LIBSGX_USTDC_A) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS)
$(LIBOCCLUM_PAL_SO): $(LIBSGX_USTDC_A) $(EDL_C_OBJS) $(C_OBJS) $(CXX_OBJS)
@$(CXX) $^ -o $@ $(LINK_FLAGS)
@echo "LINK => $@"
$(BUILD_DIR)/src/pal/Enclave_u.o: $(BUILD_DIR)/src/pal/Enclave_u.c
$(BUILD_DIR)/src/pal/src/Enclave_u.o: $(BUILD_DIR)/src/pal/src/Enclave_u.c
@$(CC) $(C_FLAGS) -c $< -o $@
@echo "CC <= $@"
$(BUILD_DIR)/src/pal/Enclave_u.c: $(SGX_EDGER8R) ../Enclave.edl
@cd $(BUILD_DIR)/src/pal && $(SGX_EDGER8R) --untrusted $(CUR_DIR)/../Enclave.edl --search-path $(SGX_SDK)/include --search-path $(RUST_SGX_SDK_DIR)/edl/
$(BUILD_DIR)/src/pal/src/Enclave_u.c: $(SGX_EDGER8R) ../Enclave.edl
@cd $(BUILD_DIR)/src/pal/src && $(SGX_EDGER8R) --untrusted $(CUR_DIR)/../Enclave.edl --search-path $(SGX_SDK)/include --search-path $(RUST_SGX_SDK_DIR)/edl/
@echo "GEN <= $@"
$(BUILD_DIR)/src/pal/%.o: %.c
@ -52,4 +53,4 @@ $(LIBSGX_USTDC_A):
@echo "GEN <= $@"
clean:
@-$(RM) -f $(BIN) $(LIBSGX_USTDC_A) $(C_OBJS) $(CXX_OBJS) $(EDL_C_OBJS) $(EDL_C_SRCS)
@-$(RM) -f $(LIBOCCLUM_PAL_SO) $(LIBSGX_USTDC_A) $(C_OBJS) $(CXX_OBJS) $(EDL_C_OBJS) $(EDL_C_SRCS)

@ -1,16 +0,0 @@
#ifndef __ATOMIC_H_
#define __ATOMIC_H_
static inline int a_load(volatile int* n) {
return *(volatile int*)n;
}
static inline void a_store(volatile int* n, int x) {
*n = x;
}
static inline int a_fetch_and_add(volatile int* n, int a) {
return __sync_fetch_and_add(n, a);
}
#endif /* __ATOMIC_H_ */

@ -1,32 +0,0 @@
#include <stddef.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <limits.h>
#include <linux/futex.h>
static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6)
{
unsigned long ret;
register long r10 __asm__("r10") = a4;
register long r8 __asm__("r8") = a5;
register long r9 __asm__("r9") = a6;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
"d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory");
return ret;
}
#define syscall(num, a1, a2, a3, a4, a5, a6) \
__syscall6((num), (long)(a1), (long)(a2), (long)(a3), (long)(a4), (long)(a5), (long)(a6))
static inline int futex(volatile void *addr1, int op, int val1, struct timespec *timeout,
void *addr2, int val3) {
return (int) syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
}
int futex_wait(volatile int* uaddr, int val) {
return futex(uaddr, FUTEX_WAIT, val, NULL, NULL, 0);
}
int futex_wakeup(volatile int* uaddr) {
return futex(uaddr, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
}

@ -1,9 +0,0 @@
#ifndef __FUTEX_H_
#define __FUTEX_H_
#include <sys/time.h>
int futex_wait(volatile int* uaddr, int val);
int futex_wakeup(volatile int* uaddr);
#endif /* __ATOMIC_H_ */

@ -0,0 +1,48 @@
#ifndef __OCCLUM_PAL_API_H__
#define __OCCLUM_PAL_API_H__
#ifdef __cplusplus
extern "C" {
#endif
/*
* @brief Initialize an Occlum enclave
*
* @param instance_dir Specifies the path of an Occlum instance directory.
* Usually, this directory is initialized by executing
* "occlum init" command, which creates a hidden
* directory named ".occlum/". This ".occlum/" is an
* Occlum instance directory. The name of the directory is
* not necesarrily ".occlum"; it can be renamed to an
* arbitrary name.
*
* @retval If 0, then success; otherwise, check errno for the exact error type.
*/
int occlum_pal_init(const char* instance_dir);
/*
* @brief Execute a command inside the Occlum enclave
*
* @param cmd_path The path of the command to be executed
* @param cmd_args The arguments to the command. The array must be NULL
* terminated.
* @param exit_status Output. The exit status of the command. Note that the
* exit status is returned if and only if the function
* succeeds.
*
* @retval If 0, then success; otherwise, check errno for the exact error type.
*/
int occlum_pal_exec(const char* cmd_path, const char** cmd_args, int* exit_status);
/*
* @brief Destroy teh Occlum enclave
*
* @retval if 0, then success; otherwise, check errno for the exact error type.
*/
int occlum_pal_destroy(void);
#ifdef __cplusplus
}
#endif
#endif /* __OCCLUM_PAL_API_H__ */

@ -1,423 +0,0 @@
#include "Enclave_u.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <pwd.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sgx_eid.h>
#include <sgx_error.h>
#include <sgx_urts.h>
#include "task.h"
#define MAX_PATH FILENAME_MAX
#define TOKEN_FILENAME "enclave.token"
#define ENCLAVE_FILENAME "libocclum.signed.so"
// ==========================================================================
// Enclave Initialization
// ==========================================================================
static sgx_enclave_id_t global_eid = 0;
typedef struct _sgx_errlist_t {
sgx_status_t err;
const char *msg;
const char *sug; /* Suggestion */
} sgx_errlist_t;
/* Error code returned by sgx_create_enclave */
static sgx_errlist_t sgx_errlist[] = {
{
SGX_ERROR_UNEXPECTED,
"Unexpected error occurred.",
NULL
},
{
SGX_ERROR_INVALID_PARAMETER,
"Invalid parameter.",
NULL
},
{
SGX_ERROR_OUT_OF_MEMORY,
"Out of memory.",
NULL
},
{
SGX_ERROR_ENCLAVE_LOST,
"Power transition occurred.",
"Please refer to the sample \"PowerTransition\" for details."
},
{
SGX_ERROR_INVALID_ENCLAVE,
"Invalid enclave image.",
NULL
},
{
SGX_ERROR_INVALID_ENCLAVE_ID,
"Invalid enclave identification.",
NULL
},
{
SGX_ERROR_INVALID_SIGNATURE,
"Invalid enclave signature.",
NULL
},
{
SGX_ERROR_OUT_OF_EPC,
"Out of EPC memory.",
NULL
},
{
SGX_ERROR_NO_DEVICE,
"Invalid SGX device.",
"Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards."
},
{
SGX_ERROR_MEMORY_MAP_CONFLICT,
"Memory map conflicted.",
NULL
},
{
SGX_ERROR_INVALID_METADATA,
"Invalid enclave metadata.",
NULL
},
{
SGX_ERROR_DEVICE_BUSY,
"SGX device was busy.",
NULL
},
{
SGX_ERROR_INVALID_VERSION,
"Enclave version was invalid.",
NULL
},
{
SGX_ERROR_INVALID_ATTRIBUTE,
"Enclave was not authorized.",
NULL
},
{
SGX_ERROR_ENCLAVE_FILE_ACCESS,
"Can't open enclave file.",
NULL
},
{
SGX_ERROR_SERVICE_INVALID_PRIVILEGE,
"Enclave has no privilege to get run in the release mode.",
"Please rebuild the Occlum enclave with a legal signing key "
"(e.g., occlum build --sign-key <key_path>), "
"to get a legal signing key, please contact Intel."
},
};
/* Check error conditions for loading enclave */
static void print_error_message(sgx_status_t ret) {
size_t idx = 0;
size_t ttl = sizeof sgx_errlist/sizeof sgx_errlist[0];
for (idx = 0; idx < ttl; idx++) {
if(ret == sgx_errlist[idx].err) {
printf("Error: %s\n", sgx_errlist[idx].msg);
if(NULL != sgx_errlist[idx].sug)
printf("Info: %s\n", sgx_errlist[idx].sug);
break;
}
}
if (idx == ttl)
printf("Error: Unexpected error occurred.\n");
}
static const char* get_enclave_absolute_path() {
static char enclave_path[MAX_PATH] = {0};
// Get the absolute path of the executable
readlink("/proc/self/exe", enclave_path, sizeof(enclave_path));
// Get the absolute path of the containing directory
dirname(enclave_path);
// Get the absolute path of the enclave
strncat(enclave_path, "/../lib/", sizeof(enclave_path));
strncat(enclave_path, ENCLAVE_FILENAME, sizeof(enclave_path));
return (const char*)enclave_path;
}
/* Get enclave debug flag according to env "OCCLUM_RELEASE_ENCLAVE" */
static int get_enclave_debug_flag() {
const char* release_enclave_val = getenv("OCCLUM_RELEASE_ENCLAVE");
if (release_enclave_val) {
if (!strcmp(release_enclave_val, "1") ||
!strcasecmp(release_enclave_val, "y") ||
!strcasecmp(release_enclave_val, "yes") ||
!strcasecmp(release_enclave_val, "true")) {
return 0;
}
}
return 1;
}
/* Initialize the enclave:
* Step 1: try to retrieve the launch token saved by last transaction
* Step 2: call sgx_create_enclave to initialize an enclave instance
* Step 3: save the launch token if it is updated
*/
static int initialize_enclave()
{
char token_path[MAX_PATH] = {'\0'};
sgx_launch_token_t token = {0};
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
int updated = 0;
/* Step 1: try to retrieve the launch token saved by last transaction
* if there is no token, then create a new one.
*/
/* try to get the token saved in $HOME */
const char *home_dir = getpwuid(getuid())->pw_dir;
if (home_dir != NULL &&
(strlen(home_dir)+strlen("/")+sizeof(TOKEN_FILENAME)+1) <= MAX_PATH) {
/* compose the token path */
strncpy(token_path, home_dir, strlen(home_dir));
strncat(token_path, "/", strlen("/"));
strncat(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME)+1);
} else {
/* if token path is too long or $HOME is NULL */
strncpy(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME));
}
FILE *fp = fopen(token_path, "rb");
if (fp == NULL && (fp = fopen(token_path, "wb")) == NULL) {
printf("Warning: Failed to create/open the launch token file \"%s\".\n", token_path);
}
if (fp != NULL) {
/* read the token from saved file */
size_t read_num = fread(token, 1, sizeof(sgx_launch_token_t), fp);
if (read_num != 0 && read_num != sizeof(sgx_launch_token_t)) {
/* if token is invalid, clear the buffer */
memset(&token, 0x0, sizeof(sgx_launch_token_t));
printf("Warning: Invalid launch token read from \"%s\".\n", token_path);
}
}
/* Step 2: call sgx_create_enclave to initialize an enclave instance */
/* Debug Support: set 2nd parameter to 1 */
const char* enclave_path = get_enclave_absolute_path();
int sgx_debug_flag = get_enclave_debug_flag();
ret = sgx_create_enclave(enclave_path, sgx_debug_flag, &token, &updated, &global_eid, NULL);
if (ret != SGX_SUCCESS) {
print_error_message(ret);
if (fp != NULL) fclose(fp);
return -1;
}
/* Step 3: save the launch token if it is updated */
if (updated == 0 || fp == NULL) {
/* if the token is not updated, or file handler is invalid, do not perform saving */
if (fp != NULL) fclose(fp);
return 0;
}
/* reopen the file with write capablity */
fp = freopen(token_path, "wb", fp);
if (fp == NULL) return 0;
size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp);
if (write_num != sizeof(sgx_launch_token_t))
printf("Warning: Failed to save launch token to \"%s\".\n", token_path);
fclose(fp);
return 0;
}
// ==========================================================================
// OCalls
// ==========================================================================
void ocall_print_string(const char* msg) {
printf("%s", msg);
}
int ocall_run_new_task(void) {
int ret = run_new_task(global_eid);
return ret;
}
void ocall_gettimeofday(long* seconds, long* microseconds) {
struct timeval tv;
gettimeofday(&tv, NULL);
*seconds = tv.tv_sec;
*microseconds = tv.tv_usec;
}
void ocall_clock_gettime(int clockid, time_t* sec, long* ns) {
struct timespec ts;
clock_gettime(clockid, &ts);
*sec = ts.tv_sec;
*ns = ts.tv_nsec;
}
void ocall_nanosleep(time_t sec, long nsec) {
struct timespec tv = { .tv_sec = sec, .tv_nsec = nsec };
nanosleep(&tv, NULL);
}
int ocall_sched_getaffinity(int* error, int pid, size_t cpusize, unsigned char* buf) {
int ret = syscall(__NR_sched_getaffinity, pid, cpusize, buf);
if (error) {
*error = (ret == -1) ? errno : 0;
}
return ret;
}
int ocall_sched_setaffinity(int* error, int pid, size_t cpusize, const unsigned char* buf) {
int ret = syscall(__NR_sched_setaffinity, pid, cpusize, buf);
if (error) {
*error = (ret == -1) ? errno : 0;
}
return ret;
}
/* In the Linux implementation, sched_yield() always succeeds */
void ocall_sched_yield(void) {
sched_yield();
}
void ocall_sync(void) {
sync();
}
ssize_t ocall_sendmsg(int sockfd,
const void *msg_name,
socklen_t msg_namelen,
const void *buf,
size_t buf_len,
const void *msg_control,
size_t msg_controllen,
int flags)
{
struct iovec msg_iov = { .iov_base = (void*)buf, .iov_len = buf_len };
struct iovec* p_msg_iov = buf != NULL ? &msg_iov : NULL;
size_t msg_iovlen = buf != NULL ? 1 : 0;
struct msghdr msg = {
(void*) msg_name,
msg_namelen,
p_msg_iov,
msg_iovlen,
(void*) msg_control,
msg_controllen,
0,
};
return sendmsg(sockfd, &msg, flags);
}
ssize_t ocall_recvmsg(int sockfd,
void *msg_name,
socklen_t msg_namelen,
socklen_t* msg_namelen_recv,
void *buf,
size_t buf_len,
void *msg_control,
size_t msg_controllen,
size_t* msg_controllen_recv,
int* msg_flags_recv,
int flags)
{
struct iovec msg_iov = { .iov_base = buf, .iov_len = buf_len };
struct iovec* p_msg_iov = buf != NULL ? &msg_iov : NULL;
size_t msg_iovlen = buf != NULL ? 1 : 0;
struct msghdr msg = {
msg_name,
msg_namelen,
p_msg_iov,
msg_iovlen,
msg_control,
msg_controllen,
0,
};
ssize_t ret = recvmsg(sockfd, &msg, flags);
if (ret < 0) return ret;
*msg_namelen_recv = msg.msg_namelen;
*msg_controllen_recv = msg.msg_controllen;
*msg_flags_recv = msg.msg_flags;
return ret;
}
// ==========================================================================
// Main
// ==========================================================================
/* Application entry */
int SGX_CDECL main(int argc, const char *argv[])
{
struct timeval startup, libosready, appdie;
gettimeofday(&startup, NULL);
sgx_status_t sgx_ret = SGX_SUCCESS;
int status = 0;
if (argc < 2) {
printf("ERROR: at least one argument must be provided\n\n");
printf("Usage: pal <executable> <arg1> <arg2>...\n");
return EXIT_FAILURE;
}
const char* executable_path = argv[1];
/* Initialize the enclave */
if (initialize_enclave() < 0){
printf("Enter a character before exit ...\n");
getchar();
return EXIT_FAILURE;
}
// First ecall do a lot initializations.
// Count it as startup time.
dummy_ecall(global_eid, &status);
gettimeofday(&libosready, NULL);
sgx_ret = libos_boot(global_eid, &status, executable_path, &argv[2]);
if (sgx_ret != SGX_SUCCESS) {
print_error_message(sgx_ret);
return EXIT_FAILURE;
}
if (status != 0) {
return EXIT_FAILURE;
}
// TODO: exit all tasks gracefully, instead of killing all remaining
// tasks automatically after the main task exits and the process
// terminates.
//status = wait_all_tasks();
status = wait_main_task();
gettimeofday(&appdie, NULL);
uint64_t libos_startup_time, app_runtime;
libos_startup_time = (libosready.tv_sec - startup.tv_sec) * 1000000 + (libosready.tv_usec - startup.tv_usec);
app_runtime = (appdie.tv_sec - libosready.tv_sec) * 1000000 + (appdie.tv_usec - libosready.tv_usec);
printf("LibOS startup time: %lu microseconds\n", libos_startup_time);
printf("Apps running time: %lu microseconds\n", app_runtime);
// TODO: destroy the enclave gracefully
// We cannot destroy the enclave gracefully since we may still have
// running threads that are using the enclave at this point, which blocks
// sgx_destory_enclave call. This issue is related to "TODO: exit all tasks
// gracefully" above.
//sgx_destroy_enclave(global_eid);
return status;
}

8
src/pal/pal.lds Normal file

@ -0,0 +1,8 @@
{
global:
occlum_pal_init;
occlum_pal_exec;
occlum_pal_destroy;
local:
*;
};

@ -1,13 +1,14 @@
#include "sgx_uae_service.h"
#include <sgx_uae_service.h>
#include "ocalls.h"
sgx_status_t ocall_sgx_init_quote(
sgx_target_info_t *target_info,
sgx_epid_group_id_t *epid_group_id)
sgx_status_t occlum_ocall_sgx_init_quote(
sgx_target_info_t* target_info,
sgx_epid_group_id_t* epid_group_id)
{
return sgx_init_quote(target_info, epid_group_id);
}
sgx_status_t ocall_sgx_get_quote(
sgx_status_t occlum_ocall_sgx_get_quote(
uint8_t* sigrl,
uint32_t sigrl_len,
sgx_report_t* report,

6
src/pal/src/ocalls/fs.c Normal file

@ -0,0 +1,6 @@
#include <unistd.h>
#include "ocalls.h"
void occlum_ocall_sync(void) {
sync();
}

63
src/pal/src/ocalls/net.c Normal file

@ -0,0 +1,63 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <stddef.h>
#include "ocalls.h"
ssize_t occlum_ocall_sendmsg(int sockfd,
const void *msg_name,
socklen_t msg_namelen,
const void *buf,
size_t buf_len,
const void *msg_control,
size_t msg_controllen,
int flags)
{
struct iovec msg_iov = { .iov_base = (void*)buf, .iov_len = buf_len };
struct iovec* p_msg_iov = buf != NULL ? &msg_iov : NULL;
size_t msg_iovlen = buf != NULL ? 1 : 0;
struct msghdr msg = {
(void*) msg_name,
msg_namelen,
p_msg_iov,
msg_iovlen,
(void*) msg_control,
msg_controllen,
0,
};
return sendmsg(sockfd, &msg, flags);
}
ssize_t occlum_ocall_recvmsg(int sockfd,
void *msg_name,
socklen_t msg_namelen,
socklen_t* msg_namelen_recv,
void *buf,
size_t buf_len,
void *msg_control,
size_t msg_controllen,
size_t* msg_controllen_recv,
int* msg_flags_recv,
int flags)
{
struct iovec msg_iov = { .iov_base = buf, .iov_len = buf_len };
struct iovec* p_msg_iov = buf != NULL ? &msg_iov : NULL;
size_t msg_iovlen = buf != NULL ? 1 : 0;
struct msghdr msg = {
msg_name,
msg_namelen,
p_msg_iov,
msg_iovlen,
msg_control,
msg_controllen,
0,
};
ssize_t ret = recvmsg(sockfd, &msg, flags);
if (ret < 0) return ret;
*msg_namelen_recv = msg.msg_namelen;
*msg_controllen_recv = msg.msg_controllen;
*msg_flags_recv = msg.msg_flags;
return ret;
}

@ -0,0 +1,5 @@
#include "Enclave_u.h"
#include "../pal_enclave.h"
#include "../pal_error.h"
#include "../pal_syscall.h"
#include "../pal_log.h"

@ -0,0 +1,24 @@
#include <sched.h>
#include "ocalls.h"
int occlum_ocall_sched_getaffinity(int* error, int pid, size_t cpusize, unsigned char* buf) {
int ret = syscall(__NR_sched_getaffinity, pid, cpusize, buf);
if (error) {
*error = (ret == -1) ? errno : 0;
}
return ret;
}
int occlum_ocall_sched_setaffinity(int* error, int pid, size_t cpusize, const unsigned char* buf) {
int ret = syscall(__NR_sched_setaffinity, pid, cpusize, buf);
if (error) {
*error = (ret == -1) ? errno : 0;
}
return ret;
}
/* In the Linux implementation, sched_yield() always succeeds */
void occlum_ocall_sched_yield(void) {
sched_yield();
}

@ -0,0 +1,45 @@
#include <stdlib.h>
#include <pthread.h>
#include "ocalls.h"
typedef struct {
sgx_enclave_id_t enclave_id;
int libos_tid;
} thread_data_t;
void* exec_libos_thread(void* _thread_data) {
thread_data_t* thread_data = _thread_data;
sgx_enclave_id_t eid = thread_data->enclave_id;
int host_tid = gettid();
int libos_tid = thread_data->libos_tid;
int libos_exit_status = -1;
sgx_status_t status = occlum_ecall_exec_thread(eid, &libos_exit_status, libos_tid, host_tid);
if (status != SGX_SUCCESS) {
const char* sgx_err = pal_get_sgx_error_msg(status);
PAL_ERROR("Failed to enter the enclave to execute a LibOS thread: %s", sgx_err);
exit(EXIT_FAILURE);
}
free(thread_data);
return NULL;
}
// Start a new host OS thread and enter the enclave to execute the LibOS thread
int occlum_ocall_exec_thread_async(int libos_tid) {
int ret = 0;
pthread_t thread;
thread_data_t* thread_data = malloc(sizeof *thread_data);
thread_data->enclave_id = pal_get_enclave_id();
thread_data->libos_tid = libos_tid;
if ((ret = pthread_create(&thread, NULL, exec_libos_thread, thread_data)) < 0) {
free(thread_data);
return -1;
}
pthread_detach(thread);
// Note: thread_data is freed just before the thread exits
return 0;
}

21
src/pal/src/ocalls/time.c Normal file

@ -0,0 +1,21 @@
#include <sys/time.h>
#include "ocalls.h"
void occlum_ocall_gettimeofday(long* seconds, long* microseconds) {
struct timeval tv;
gettimeofday(&tv, NULL);
*seconds = tv.tv_sec;
*microseconds = tv.tv_usec;
}
void occlum_ocall_clock_gettime(int clockid, time_t* sec, long* ns) {
struct timespec ts;
clock_gettime(clockid, &ts);
*sec = ts.tv_sec;
*ns = ts.tv_nsec;
}
void occlum_ocall_nanosleep(time_t sec, long nsec) {
struct timespec tv = { .tv_sec = sec, .tv_nsec = nsec };
nanosleep(&tv, NULL);
}

93
src/pal/src/pal_api.c Normal file

@ -0,0 +1,93 @@
#include <occlum_pal_api.h>
#include "Enclave_u.h"
#include "pal_enclave.h"
#include "pal_error.h"
#include "pal_log.h"
#include "pal_syscall.h"
int occlum_pal_init(const char* instance_dir) {
errno = 0;
if (instance_dir == NULL) {
errno = EINVAL;
return -1;
}
sgx_enclave_id_t eid = pal_get_enclave_id();
if (eid != SGX_INVALID_ENCLAVE_ID) {
PAL_ERROR("Enclave has been initialized.");
errno = EEXIST;
return -1;
}
if (pal_init_enclave(instance_dir) < 0) {
return -1;
}
// Invoke a do-nothing ECall for two purposes:
// 1) Test the enclave can work;
// 2) Initialize the global data structures inside the enclave (which is
// automatically done by Intel SGX SDK).
eid = pal_get_enclave_id();
sgx_status_t ecall_status = occlum_ecall_nop(eid);
if (ecall_status != SGX_SUCCESS) {
const char* sgx_err = pal_get_sgx_error_msg(ecall_status);
PAL_ERROR("Failed to do ECall: %s", sgx_err);
return -1;
}
return 0;
}
int occlum_pal_exec(const char* cmd_path, const char** cmd_args, int* exit_status) {
errno = 0;
if (cmd_path == NULL || cmd_args == NULL || exit_status == NULL) {
errno = EINVAL;
return -1;
}
sgx_enclave_id_t eid = pal_get_enclave_id();
if (eid == SGX_INVALID_ENCLAVE_ID) {
PAL_ERROR("Enclave is not initialized yet.");
errno = ENOENT;
return -1;
}
int libos_tid = -1;
sgx_status_t ecall_status = occlum_ecall_new_process(eid, &libos_tid, cmd_path, cmd_args);
if (ecall_status != SGX_SUCCESS) {
const char* sgx_err = pal_get_sgx_error_msg(ecall_status);
PAL_ERROR("Failed to do ECall: %s", sgx_err);
return -1;
}
if (libos_tid < 0) {
return -1;
}
int host_tid = gettid();
ecall_status = occlum_ecall_exec_thread(eid, exit_status, libos_tid, host_tid);
if (ecall_status != SGX_SUCCESS) {
const char* sgx_err = pal_get_sgx_error_msg(ecall_status);
PAL_ERROR("Failed to do ECall: %s", sgx_err);
return -1;
}
return 0;
}
int occlum_pal_destroy(void) {
errno = 0;
sgx_enclave_id_t eid = pal_get_enclave_id();
if (eid == SGX_INVALID_ENCLAVE_ID) {
PAL_ERROR("Enclave is not initialized yet.");
errno = ENOENT;
return -1;
}
if (pal_destroy_enclave() < 0) {
return -1;
}
return 0;
}

138
src/pal/src/pal_enclave.c Normal file

@ -0,0 +1,138 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <pwd.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sgx_eid.h>
#include <sgx_error.h>
#include <sgx_urts.h>
#include "pal_enclave.h"
#include "pal_error.h"
#include "pal_log.h"
#define MAX_PATH FILENAME_MAX
#define TOKEN_FILENAME "enclave.token"
#define ENCLAVE_FILENAME "libocclum-libos.signed.so"
static sgx_enclave_id_t global_eid = SGX_INVALID_ENCLAVE_ID;
/* Get enclave debug flag according to env "OCCLUM_RELEASE_ENCLAVE" */
static int get_enclave_debug_flag() {
const char* release_enclave_val = getenv("OCCLUM_RELEASE_ENCLAVE");
if (release_enclave_val) {
if (!strcmp(release_enclave_val, "1") ||
!strcasecmp(release_enclave_val, "y") ||
!strcasecmp(release_enclave_val, "yes") ||
!strcasecmp(release_enclave_val, "true")) {
return 0;
}
}
return 1;
}
static const char* get_enclave_absolute_path(const char* instance_dir) {
static char enclave_path[MAX_PATH + 1] = {0};
strncat(enclave_path, instance_dir, MAX_PATH);
strncat(enclave_path, "/build/lib/", MAX_PATH);
strncat(enclave_path, ENCLAVE_FILENAME, MAX_PATH);
return (const char*)enclave_path;
}
/* Initialize the enclave:
* Step 1: try to retrieve the launch token saved by last transaction
* Step 2: call sgx_create_enclave to initialize an enclave instance
* Step 3: save the launch token if it is updated
*/
int pal_init_enclave(const char* instance_dir) {
char token_path[MAX_PATH] = {'\0'};
sgx_launch_token_t token = {0};
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
int updated = 0;
/* Step 1: try to retrieve the launch token saved by last transaction
* if there is no token, then create a new one.
*/
/* try to get the token saved in $HOME */
const char *home_dir = getpwuid(getuid())->pw_dir;
if (home_dir != NULL &&
(strlen(home_dir)+strlen("/")+sizeof(TOKEN_FILENAME)+1) <= MAX_PATH) {
/* compose the token path */
strncpy(token_path, home_dir, strlen(home_dir));
strncat(token_path, "/", strlen("/"));
strncat(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME)+1);
} else {
/* if token path is too long or $HOME is NULL */
strncpy(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME));
}
FILE *fp = fopen(token_path, "rb");
if (fp == NULL && (fp = fopen(token_path, "wb")) == NULL) {
PAL_WARN("Warning: Failed to create/open the launch token file \"%s\".\n", token_path);
}
if (fp != NULL) {
/* read the token from saved file */
size_t read_num = fread(token, 1, sizeof(sgx_launch_token_t), fp);
if (read_num != 0 && read_num != sizeof(sgx_launch_token_t)) {
/* if token is invalid, clear the buffer */
memset(&token, 0x0, sizeof(sgx_launch_token_t));
PAL_WARN("Invalid launch token read from \"%s\".\n", token_path);
}
}
/* Step 2: call sgx_create_enclave to initialize an enclave instance */
/* Debug Support: set 2nd parameter to 1 */
const char* enclave_path = get_enclave_absolute_path(instance_dir);
int sgx_debug_flag = get_enclave_debug_flag();
ret = sgx_create_enclave(enclave_path, sgx_debug_flag, &token, &updated, &global_eid, NULL);
if (ret != SGX_SUCCESS) {
const char* sgx_err_msg = pal_get_sgx_error_msg(ret);
PAL_ERROR("Failed to create enclave: %s", sgx_err_msg);
if (fp != NULL) fclose(fp);
return -1;
}
/* Step 3: save the launch token if it is updated */
if (updated == 0 || fp == NULL) {
/* if the token is not updated, or file handler is invalid, do not perform saving */
if (fp != NULL) fclose(fp);
return 0;
}
/* reopen the file with write capablity */
fp = freopen(token_path, "wb", fp);
if (fp == NULL) return 0;
size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp);
if (write_num != sizeof(sgx_launch_token_t))
PAL_WARN("Warning: Failed to save launch token to \"%s\".\n", token_path);
fclose(fp);
return 0;
}
int pal_destroy_enclave(void) {
// TODO: destroy the enclave gracefully
// We cannot destroy the enclave gracefully since we may still have
// running threads that are using the enclave at this point, which blocks
// sgx_destory_enclave call. We need to implement exit_group syscall and
// handle signal and exceptions properly.
//sgx_destroy_enclave(global_eid);
return 0;
}
sgx_enclave_id_t pal_get_enclave_id(void) {
return global_eid;
}

12
src/pal/src/pal_enclave.h Normal file

@ -0,0 +1,12 @@
#ifndef __PAL_ENCLAVE_H__
#define __PAL_ENCLAVE_H__
#include <sgx_eid.h>
int pal_init_enclave(const char* instance_dir);
int pal_destroy_enclave(void);
#define SGX_INVALID_ENCLAVE_ID (-1)
sgx_enclave_id_t pal_get_enclave_id(void);
#endif /* __PAL_ENCLAVE_H__ */

90
src/pal/src/pal_error.c Normal file

@ -0,0 +1,90 @@
#include "pal_error.h"
typedef struct {
sgx_status_t err;
const char *msg;
} sgx_err_msg_t;
static sgx_err_msg_t err_msg_table[] = {
{
SGX_SUCCESS,
"SGX success."
},
{
SGX_ERROR_UNEXPECTED,
"Unexpected error occurred."
},
{
SGX_ERROR_INVALID_PARAMETER,
"Invalid parameter."
},
{
SGX_ERROR_OUT_OF_MEMORY,
"Out of memory."
},
{
SGX_ERROR_ENCLAVE_LOST,
"Power transition occurred."
},
{
SGX_ERROR_INVALID_ENCLAVE,
"Invalid enclave image."
},
{
SGX_ERROR_INVALID_ENCLAVE_ID,
"Invalid enclave identification."
},
{
SGX_ERROR_INVALID_SIGNATURE,
"Invalid enclave signature."
},
{
SGX_ERROR_OUT_OF_EPC,
"Out of EPC memory."
},
{
SGX_ERROR_NO_DEVICE,
"Invalid SGX device. Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards."
},
{
SGX_ERROR_MEMORY_MAP_CONFLICT,
"Memory map conflicted."
},
{
SGX_ERROR_INVALID_METADATA,
"Invalid enclave metadata."
},
{
SGX_ERROR_DEVICE_BUSY,
"SGX device was busy."
},
{
SGX_ERROR_INVALID_VERSION,
"Enclave version was invalid."
},
{
SGX_ERROR_INVALID_ATTRIBUTE,
"Enclave was not authorized."
},
{
SGX_ERROR_ENCLAVE_FILE_ACCESS,
"Can't open enclave file."
},
{
SGX_ERROR_SERVICE_INVALID_PRIVILEGE,
"Enclave has no privilege to get run in the release mode."
"Please rebuild the Occlum enclave with a legal signing key "
"(e.g., occlum build --sign-key <key_path>), "
"to get a legal signing key, please contact Intel."
},
};
const char* pal_get_sgx_error_msg(sgx_status_t error) {
int err_max = sizeof err_msg_table/sizeof err_msg_table[0];
for (int err_i = 0; err_i < err_max; err_i++) {
if(error == err_msg_table[err_i].err) {
return err_msg_table[err_i].msg;
}
}
return "Unknown SGX error";
}

9
src/pal/src/pal_error.h Normal file

@ -0,0 +1,9 @@
#ifndef __PAL_ERROR_H__
#define __PAL_ERROR_H__
#include <errno.h>
#include <sgx_error.h>
const char* pal_get_sgx_error_msg(sgx_status_t error);
#endif /* __PAL_ERROR_H__ */

15
src/pal/src/pal_log.h Normal file

@ -0,0 +1,15 @@
#ifndef __PAL_LOG_H__
#define __PAL_LOG_H__
#include <stdio.h>
#define PAL_DEBUG(fmt, ...) \
fprintf(stderr, "[DEBUG] occlum-pal: " fmt " (line %d, file %s)\n", ##__VA_ARGS__, __LINE__, __FILE__)
#define PAL_INFO(fmt, ...) \
fprintf(stderr, "[INFO] occlum-pal: " fmt " (line %d, file %s)\n", ##__VA_ARGS__, __LINE__, __FILE__)
#define PAL_WARN(fmt, ...) \
fprintf(stderr, "[WARM] occlum-pal: " fmt " (line %d, file %s)\n", ##__VA_ARGS__, __LINE__, __FILE__)
#define PAL_ERROR(fmt, ...) \
fprintf(stderr, "[ERROR] occlum-pal: " fmt " (line %d, file %s)\n", ##__VA_ARGS__, __LINE__, __FILE__)
#endif /* __PAL_LOG_H__ */

10
src/pal/src/pal_syscall.h Normal file

@ -0,0 +1,10 @@
#ifndef __PAL_SYSCALL_H__
#define __PAL_SYSCALL_H__
#define _GNU_SOURCE
#include <sys/syscall.h>
#include <unistd.h>
#define gettid() syscall(__NR_gettid)
#endif /* __PAL_SYSCALL_H__ */

@ -1,91 +0,0 @@
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include "atomic.h"
#include "futex.h"
#include "sgx_urts.h"
#include "Enclave_u.h"
int syscall();
#define gettid() syscall(__NR_gettid)
static volatile int num_tasks = 0;
static volatile int any_fatal_error = 0;
// The LibOS never returns INT_MIN. As long as the main_task_status == INT_MIN,
// the main task must not have returned.
#define MAIN_TASK_NOT_RETURNED INT_MIN
static volatile int main_task_status = MAIN_TASK_NOT_RETURNED;
static int BEGIN_TASK(void) {
return a_fetch_and_add(&num_tasks, 1) == 0;
}
static void END_TASK(void) {
if (a_fetch_and_add(&num_tasks, -1) == 1) {
futex_wakeup(&num_tasks);
}
}
struct task_thread_data {
int is_main_task;
sgx_enclave_id_t eid;
};
static void* __run_task_thread(void* _data) {
int status = 0;
struct task_thread_data* data = _data;
sgx_status_t sgx_ret = libos_run(data->eid, &status, gettid());
if(sgx_ret != SGX_SUCCESS) {
// TODO: deal with ECALL error
printf("ERROR: ECall libos_run failed\n");
any_fatal_error = 1;
}
if (data->is_main_task) {
a_store(&main_task_status, status);
futex_wakeup(&main_task_status);
}
free(data);
END_TASK();
return NULL;
}
int run_new_task(sgx_enclave_id_t eid) {
int ret = 0;
pthread_t thread;
struct task_thread_data* data = malloc(sizeof(*data));
data->is_main_task = BEGIN_TASK();
data->eid = eid;
if ((ret = pthread_create(&thread, NULL, __run_task_thread, data)) < 0) {
free(data);
END_TASK();
return ret;
}
pthread_detach(thread);
return 0;
}
int wait_main_task(void) {
while ((a_load(&main_task_status)) == MAIN_TASK_NOT_RETURNED) {
futex_wait(&main_task_status, MAIN_TASK_NOT_RETURNED);
}
return main_task_status;
}
int wait_all_tasks(void) {
int cur_num_tasks;
while ((cur_num_tasks = a_load(&num_tasks)) != 0) {
futex_wait(&num_tasks, cur_num_tasks);
}
return any_fatal_error ? -1 : main_task_status;
}

@ -1,8 +0,0 @@
#ifndef __TASK_H_
#define __TASK_H_
int run_new_task(sgx_enclave_id_t eid);
int wait_all_tasks(void);
int wait_main_task(void);
#endif /* __TASK_H_ */

30
src/run/Makefile Normal file

@ -0,0 +1,30 @@
include ../sgxenv.mk
BIN := $(BUILD_DIR)/bin/occlum-run
C_SRCS := $(sort $(wildcard *.c))
C_OBJS := $(addprefix $(BUILD_DIR)/src/run/,$(C_SRCS:.c=.o))
C_COMMON_FLAGS := -I$(PROJECT_DIR)/src/pal/include
C_FLAGS := $(C_COMMON_FLAGS) $(SGX_CFLAGS_U)
LINK_FLAGS := $(SGX_LFLAGS_U) -L$(BUILD_DIR)/lib -lsgx_uprotected_fs -locclum-pal
ALL_BUILD_SUBDIRS := $(sort $(patsubst %/,%,$(dir $(BIN) $(C_OBJS))))
.PHONY: all clean
all: $(ALL_BUILD_SUBDIRS) $(BIN)
$(ALL_BUILD_SUBDIRS):
@mkdir -p $@
$(BIN): $(C_OBJS)
@$(CC) $^ -o $@ $(LINK_FLAGS)
@echo "LINK => $@"
$(BUILD_DIR)/src/run/%.o: %.c
@$(CC) $(C_FLAGS) -c $< -o $@
@echo "CC <= $@"
clean:
@-$(RM) -f $(BIN) $(C_OBJS)

42
src/run/main.c Normal file

@ -0,0 +1,42 @@
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <occlum_pal_api.h>
static const char* get_instance_dir(void) {
const char* instance_dir_from_env = (const char*) getenv("OCCLUM_INSTANCE_DIR");
if (instance_dir_from_env != NULL) {
return instance_dir_from_env;
}
else {
return "./.occlum";
}
}
int main(int argc, char* argv[]) {
// Parse arguments
if (argc < 2) {
fprintf(stderr, "[ERROR] occlum-run: at least one argument must be provided\n\n");
fprintf(stderr, "Usage: occlum-run <executable> [<args>]\n");
return EXIT_FAILURE;
}
const char* cmd_path = (const char*) argv[1];
const char** cmd_args = (const char**) &argv[2];
// Init Occlum PAL
const char* instance_dir = get_instance_dir();
if (occlum_pal_init(instance_dir) < 0) {
return EXIT_FAILURE;
}
// Use Occlum PAL to execute the cmd
int exit_status = 0;
if (occlum_pal_exec(cmd_path, cmd_args, &exit_status) < 0) {
return EXIT_FAILURE;
}
// Destroy Occlum PAL
occlum_pal_destroy();
return exit_status;
}

@ -104,10 +104,11 @@ cmd_build() {
rm -rf build
mkdir -p build/bin
cp "$occlum_dir/build/bin/occlum-pal" build/bin/
cp "$occlum_dir/build/bin/occlum-run" build/bin/
mkdir -p build/lib
cp "$occlum_dir/build/lib/libocclum_core.a" build/lib/
cp "$occlum_dir/build/lib/libocclum-libos-core.a" build/lib/
cp "$occlum_dir/build/lib/libcompiler-rt-patch.a" build/lib/
cp "$occlum_dir/build/lib/libocclum-pal.so" build/lib/
mkdir -p build/src/libos/src/builtin
chmod 531 -R $working_dir/image/bin
@ -145,7 +146,7 @@ cmd_build() {
cp -r "$occlum_dir/src/libos/src/builtin" src/libos/src/builtin
cd src/libos && \
make clean-builtin && \
make "$context_dir/build/lib/libocclum.so" ONLY_REBUILD_BUILTIN=1
make "$context_dir/build/lib/libocclum-libos.so" ONLY_REBUILD_BUILTIN=1
while [ -n "$1" ]; do
case "$1" in
--sign-key) [ -n "$2" ] && ENCLAVE_SIGN_KEY=$2 ; shift 2 || exit_error "empty signing key path" ;;
@ -160,11 +161,13 @@ cmd_build() {
$ENCLAVE_SIGN_TOOL sign \
-key $ENCLAVE_SIGN_KEY \
-config "$working_dir/Enclave.xml" \
-enclave "$context_dir/build/lib/libocclum.so" \
-out "$context_dir/build/lib/libocclum.signed.so"
-enclave "$context_dir/build/lib/libocclum-libos.so" \
-out "$context_dir/build/lib/libocclum-libos.signed.so"
cd "$context_dir"
echo "built" > status
mkdir -p "$context_dir/run/mount/root"
echo "Built the Occlum image and enclave successfully"
}
@ -172,8 +175,7 @@ cmd_run() {
cd "$working_dir"
echo "running" > "$context_dir/status"
mkdir -p "$context_dir/run/mount/root"
RUST_BACKTRACE=1 "$context_dir/build/bin/occlum-pal" "$@"
RUST_BACKTRACE=1 LD_LIBRARY_PATH="$context_dir/build/lib" "$context_dir/build/bin/occlum-run" "$@"
echo "built" > "$context_dir/status"
}

@ -46,12 +46,12 @@ build_enclave_so() {
sign_enclave_so() {
cd $working_dir
rm -f libocclum.signed.so
local enclave_so_path="$project_dir/src/libos/libocclum.so"
rm -f libocclum-libos.signed.so
local enclave_so_path="$project_dir/src/libos/libocclum-libos.so"
$SGX_SDK/bin/x64/sgx_sign sign \
-key $enclave_key_pem_path \
-enclave $enclave_so_path \
-out "libocclum.signed.so" \
-out "libocclum-libos.signed.so" \
-config $enclave_conf_xml_path
}
@ -73,7 +73,7 @@ if [[ $enclave_key_pem_path != *.pem ]] ; then
fi
# ===========================================================================
# Build Occlum.json.protected and libocclum.signed.so
# Build Occlum.json.protected and libocclum-libos.signed.so
# ===========================================================================
set -e
@ -90,4 +90,4 @@ echo "EXPORT => OCCLUM_BUILTIN_VM_USER_SPACE_SIZE = $OCCLUM_BUILTIN_VM_USER_SPAC
build_enclave_so
sign_enclave_so
echo "SIGN => libocclum.signed.so"
echo "SIGN => libocclum-libos.signed.so"