diff --git a/src/Enclave.edl b/src/Enclave.edl index b3bc278d..3f32a7ac 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -10,13 +10,20 @@ enclave { include "occlum_edl_types.h" trusted { + /* + * Initialize the LibOS according to the specified attributes. + * + * @retval On success, return 0; otherwise, return -1. + */ + public int occlum_ecall_init([in, string] const char* log_level); + /* * 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. + * return -1. */ public int occlum_ecall_new_process( [in, string] const char* executable_path, @@ -28,14 +35,9 @@ enclave { * 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. + * return -1. */ 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 { diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 2e1038c1..074d38f2 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -5,13 +5,51 @@ use std::ffi::{CStr, CString, OsString}; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; +use util::log::LevelFilter; use util::mem_util::from_untrusted::*; +use util::sgx::allow_debug as sgx_allow_debug; const ENCLAVE_PATH: &'static str = ".occlum/build/lib/libocclum-libos.signed.so"; lazy_static! { static ref INIT_ONCE: Once = Once::new(); - static ref ALLOW_RUN: AtomicBool = AtomicBool::new(false); + static ref HAS_INIT: AtomicBool = AtomicBool::new(false); +} + +#[no_mangle] +pub extern "C" fn occlum_ecall_init(log_level: *const c_char) -> i32 { + if HAS_INIT.load(Ordering::SeqCst) == true { + return EXIT_STATUS_INTERNAL_ERROR; + } + + let log_level = { + let input_log_level = match parse_log_level(log_level) { + Err(e) => { + eprintln!("invalid log level: {}", e.backtrace()); + return EXIT_STATUS_INTERNAL_ERROR; + } + Ok(log_level) => log_level, + }; + // Use the input log level if and only if the enclave allows debug + if sgx_allow_debug() { + input_log_level + } else { + LevelFilter::Off + } + }; + + INIT_ONCE.call_once(|| { + // Init the log infrastructure first so that log messages will be printed afterwards + util::log::init(log_level); + // Init MPX for SFI + util::mpx_util::mpx_enable(); + // Register exception handlers (support cpuid & rdtsc for now) + register_exception_handlers(); + + HAS_INIT.store(true, Ordering::SeqCst); + }); + + 0 } #[no_mangle] @@ -19,25 +57,9 @@ 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 - use util::log::LevelFilter; - let log_level = match option_env!("LIBOS_LOG") { - Some("error") => LevelFilter::Error, - Some("warn") => LevelFilter::Warn, - Some("info") => LevelFilter::Info, - Some("debug") => LevelFilter::Debug, - Some("trace") => LevelFilter::Trace, - _ => LevelFilter::Error, // errors are printed be default - }; - util::log::init(log_level); - // Init MPX for SFI - util::mpx_util::mpx_enable(); - // Register exception handlers (support cpuid & rdtsc for now) - register_exception_handlers(); - - ALLOW_RUN.store(true, Ordering::SeqCst); - }); + if HAS_INIT.load(Ordering::SeqCst) == false { + return EXIT_STATUS_INTERNAL_ERROR; + } let (path, args) = match parse_arguments(path_buf, argv) { Ok(path_and_args) => path_and_args, @@ -61,7 +83,7 @@ pub extern "C" fn occlum_ecall_new_process( #[no_mangle] pub extern "C" fn occlum_ecall_exec_thread(libos_pid: i32, host_tid: i32) -> i32 { - if ALLOW_RUN.load(Ordering::SeqCst) == false { + if HAS_INIT.load(Ordering::SeqCst) == false { return EXIT_STATUS_INTERNAL_ERROR; } @@ -80,14 +102,36 @@ pub extern "C" fn occlum_ecall_exec_thread(libos_pid: i32, host_tid: i32) -> i32 .unwrap_or(EXIT_STATUS_INTERNAL_ERROR) } -#[no_mangle] -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 // value between 0 and 255 (inclusive). const EXIT_STATUS_INTERNAL_ERROR: i32 = -128; +fn parse_log_level(level_chars: *const c_char) -> Result { + const DEFAULT_LEVEL: LevelFilter = LevelFilter::Off; + + if level_chars.is_null() { + return Ok(DEFAULT_LEVEL); + } + + let level_string = { + let level_cstring = clone_cstring_safely(level_chars)?; + level_cstring + .into_string() + .map_err(|e| errno!(EINVAL, "log_level contains valid utf-8 data"))? + .to_lowercase() + }; + Ok(match level_string.as_str() { + "off" => LevelFilter::Off, + "error" => LevelFilter::Error, + "warn" => LevelFilter::Warn, + "info" => LevelFilter::Info, + "debug" => LevelFilter::Debug, + "trace" => LevelFilter::Trace, + _ => DEFAULT_LEVEL, // Default + }) +} + fn parse_arguments( path_ptr: *const c_char, argv: *const *const c_char, diff --git a/src/libos/src/fs/dev_fs/dev_sgx/mod.rs b/src/libos/src/fs/dev_fs/dev_sgx/mod.rs index 9df765c4..42f48c01 100644 --- a/src/libos/src/fs/dev_fs/dev_sgx/mod.rs +++ b/src/libos/src/fs/dev_fs/dev_sgx/mod.rs @@ -2,11 +2,10 @@ use super::*; -mod attestation; mod consts; -use self::attestation::*; use self::consts::*; +use util::sgx::*; #[derive(Debug)] pub struct DevSgx; diff --git a/src/libos/src/util/log.rs b/src/libos/src/util/log.rs index 8f6da021..24c9ca5d 100644 --- a/src/libos/src/util/log.rs +++ b/src/libos/src/util/log.rs @@ -96,7 +96,9 @@ impl Log for SimpleLogger { } } fn flush(&self) { - //unsafe { occlum_ocall_flush_log(); } + unsafe { + occlum_ocall_flush_log(); + } } } diff --git a/src/libos/src/util/mem_util.rs b/src/libos/src/util/mem_util.rs index ecca42d4..f04efc40 100644 --- a/src/libos/src/util/mem_util.rs +++ b/src/libos/src/util/mem_util.rs @@ -93,6 +93,9 @@ pub mod from_untrusted { // TODO: strict check! pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result { check_ptr(out_ptr)?; + if out_ptr.is_null() { + return_errno!(EINVAL, "null ptr"); + } // TODO: using from_ptr directly is not safe let cstr = unsafe { CStr::from_ptr(out_ptr) }; let cstring = CString::from(cstr); diff --git a/src/libos/src/util/mod.rs b/src/libos/src/util/mod.rs index fe4ed2b9..b7175958 100644 --- a/src/libos/src/util/mod.rs +++ b/src/libos/src/util/mod.rs @@ -4,3 +4,4 @@ pub mod log; pub mod mem_util; pub mod mpx_util; pub mod ring_buf; +pub mod sgx; diff --git a/src/libos/src/fs/dev_fs/dev_sgx/attestation/mod.rs b/src/libos/src/util/sgx/mod.rs similarity index 68% rename from src/libos/src/fs/dev_fs/dev_sgx/attestation/mod.rs rename to src/libos/src/util/sgx/mod.rs index 92072632..67577caf 100644 --- a/src/libos/src/fs/dev_fs/dev_sgx/attestation/mod.rs +++ b/src/libos/src/util/sgx/mod.rs @@ -1,4 +1,4 @@ -//! SGX attestation. +//! SGX utility. use super::*; @@ -17,3 +17,8 @@ pub use sgx_types::{ pub use self::sgx_attestation_agent::SgxAttestationAgent; pub use self::sgx_quote::SgxQuote; pub use self::sgx_report::{create_report, get_self_target, verify_report}; + +pub fn allow_debug() -> bool { + let self_report = create_report(None, None).expect("create a self report should never fail"); + (self_report.body.attributes.flags & SGX_FLAGS_DEBUG) == SGX_FLAGS_DEBUG +} diff --git a/src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_attestation_agent.rs b/src/libos/src/util/sgx/sgx_attestation_agent.rs similarity index 100% rename from src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_attestation_agent.rs rename to src/libos/src/util/sgx/sgx_attestation_agent.rs diff --git a/src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_quote.rs b/src/libos/src/util/sgx/sgx_quote.rs similarity index 100% rename from src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_quote.rs rename to src/libos/src/util/sgx/sgx_quote.rs diff --git a/src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_report.rs b/src/libos/src/util/sgx/sgx_report.rs similarity index 100% rename from src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_report.rs rename to src/libos/src/util/sgx/sgx_report.rs diff --git a/src/pal/include/edl/occlum_edl_types.h b/src/pal/include/edl/occlum_edl_types.h index 209eb7f8..c1d04be3 100644 --- a/src/pal/include/edl/occlum_edl_types.h +++ b/src/pal/include/edl/occlum_edl_types.h @@ -1,8 +1,8 @@ #ifndef __OCCLUM_EDL_TYPES__ #define __OCCLUM_EDL_TYPES__ -#include // import struct timespec -#include // import struct timeval -#include // import struct iovec +#include // import struct timespec +#include // import struct timeval +#include // import struct iovec #endif /* __OCCLUM_EDL_TYPES__ */ diff --git a/src/pal/include/occlum_pal_api.h b/src/pal/include/occlum_pal_api.h index db176f41..a52bc2b3 100644 --- a/src/pal/include/occlum_pal_api.h +++ b/src/pal/include/occlum_pal_api.h @@ -5,20 +5,42 @@ extern "C" { #endif +/* + * Occlum PAL attributes + */ +typedef struct { + // Occlum 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. + // + // Mandatory field. Must not be NULL. + const char* instance_dir; + // Log level. + // + // Specifies the log level of Occlum LibOS. Valid values: "off", "error", + // "warn", "info", and "trace". Case insensitive. + // + // Optional field. If NULL, the LibOS will treat it as "off". + const char* log_level; +} occlum_pal_attr_t; + +#define OCCLUM_PAL_ATTR_INITVAL { \ + .instance_dir = NULL, \ + .log_level = NULL \ +} + /* * @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. + * @param attr Mandatory input. Attributes for Occlum. * * @retval If 0, then success; otherwise, check errno for the exact error type. */ -int occlum_pal_init(const char* instance_dir); +int occlum_pal_init(occlum_pal_attr_t* attr); /* * @brief Execute a command inside the Occlum enclave diff --git a/src/pal/src/pal_api.c b/src/pal/src/pal_api.c index df46c165..337254f3 100644 --- a/src/pal/src/pal_api.c +++ b/src/pal/src/pal_api.c @@ -5,10 +5,14 @@ #include "pal_log.h" #include "pal_syscall.h" -int occlum_pal_init(const char* instance_dir) { +int occlum_pal_init(occlum_pal_attr_t* attr) { errno = 0; - if (instance_dir == NULL) { + if (attr == NULL) { + errno = EINVAL; + return -1; + } + if (attr->instance_dir == NULL) { errno = EINVAL; return -1; } @@ -20,7 +24,7 @@ int occlum_pal_init(const char* instance_dir) { return -1; } - if (pal_init_enclave(instance_dir) < 0) { + if (pal_init_enclave(attr->instance_dir) < 0) { return -1; } @@ -29,13 +33,17 @@ int occlum_pal_init(const char* instance_dir) { // 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); + int ret; + sgx_status_t ecall_status = occlum_ecall_init(eid, &ret, attr->log_level); 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 (ret < 0) { + errno = EINVAL; + return -1; + } return 0; } diff --git a/src/run/main.c b/src/run/main.c index 01b6dc39..d5d3eecd 100644 --- a/src/run/main.c +++ b/src/run/main.c @@ -24,8 +24,10 @@ int main(int argc, char* argv[]) { 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) { + occlum_pal_attr_t attr = OCCLUM_PAL_ATTR_INITVAL; + attr.instance_dir = get_instance_dir(); + attr.log_level = getenv("OCCLUM_LOG_LEVEL"); + if (occlum_pal_init(&attr) < 0) { return EXIT_FAILURE; } diff --git a/test/pthread/main.c b/test/pthread/main.c index 0fb98bcc..a65958de 100644 --- a/test/pthread/main.c +++ b/test/pthread/main.c @@ -8,14 +8,14 @@ // Helper macros // ============================================================================ -#define NTHREADS (4) +#define NTHREADS (3) #define STACK_SIZE (8 * 1024) // ============================================================================ // The test case of concurrent counter // ============================================================================ -#define LOCAL_COUNT (100000UL) +#define LOCAL_COUNT (1000UL) #define EXPECTED_GLOBAL_COUNT (LOCAL_COUNT * NTHREADS) struct thread_arg {