Add the support for setting log level at runtime
Now one can specify the log level of the LibOS by setting `OCCLUM_LOG_LEVEL` environment variable. The possible values are "off", "error", "warn", "info", and "trace". However, for the sake of security, the log level of a release enclave (DisableDebug = 1 in Enclave.xml) is always "off" (i.e., no log) regardless of the log level specified by the untrusted environment.
This commit is contained in:
parent
6d7cf7b9f6
commit
9713e74ed9
@ -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 {
|
||||
|
@ -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<LevelFilter> {
|
||||
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,
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
mod attestation;
|
||||
mod consts;
|
||||
|
||||
use self::attestation::*;
|
||||
use self::consts::*;
|
||||
use util::sgx::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DevSgx;
|
||||
|
@ -96,7 +96,9 @@ impl Log for SimpleLogger {
|
||||
}
|
||||
}
|
||||
fn flush(&self) {
|
||||
//unsafe { occlum_ocall_flush_log(); }
|
||||
unsafe {
|
||||
occlum_ocall_flush_log();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,9 @@ pub mod from_untrusted {
|
||||
// TODO: strict check!
|
||||
pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result<CString> {
|
||||
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);
|
||||
|
@ -4,3 +4,4 @@ pub mod log;
|
||||
pub mod mem_util;
|
||||
pub mod mpx_util;
|
||||
pub mod ring_buf;
|
||||
pub mod sgx;
|
||||
|
@ -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
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
#ifndef __OCCLUM_EDL_TYPES__
|
||||
#define __OCCLUM_EDL_TYPES__
|
||||
|
||||
#include <time.h> // import struct timespec
|
||||
#include <sys/time.h> // import struct timeval
|
||||
#include <sys/uio.h> // import struct iovec
|
||||
#include <time.h> // import struct timespec
|
||||
#include <sys/time.h> // import struct timeval
|
||||
#include <sys/uio.h> // import struct iovec
|
||||
|
||||
#endif /* __OCCLUM_EDL_TYPES__ */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user