Add argc and argv support

This commit is contained in:
Tate, Hongliang Tian 2019-01-08 19:36:29 +08:00
parent ae063cbf90
commit ad704c421f
21 changed files with 290 additions and 123 deletions

@ -7,7 +7,7 @@ enclave {
trusted {
/* define ECALLs here. */
public int libos_boot([in, string] const char* executable_path);
public int libos_boot([in, string] const char* executable_path, [user_check] char** argv);
public int libos_run(void);
};

82
src/libos/src/entry.rs Normal file

@ -0,0 +1,82 @@
use super::{*};
use util::mem_util::from_untrusted::*;
use std::ffi::{CStr, CString, OsString};
use std::path::{Path};
#[no_mangle]
pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char) -> i32 {
let (path, args) = match parse_arguments(path_buf, argv) {
Ok(path_and_args) => {
path_and_args
},
Err(_) => {
return EXIT_STATUS_INTERNAL_ERROR;
}
};
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
panic::catch_unwind(||{
backtrace::__rust_begin_short_backtrace(||{
match do_boot(&path, &args) {
Ok(()) => 0,
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
}
})
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
}
#[no_mangle]
pub extern "C" fn libos_run() -> i32 {
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
panic::catch_unwind(||{
backtrace::__rust_begin_short_backtrace(||{
match do_run() {
Ok(exit_status) => exit_status,
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
}
})
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
}
// Use 127 as a special value to indicate internal error from libos, not from
// user programs, although it is completely ok for a user program to return 127.
const EXIT_STATUS_INTERNAL_ERROR : i32 = 127;
fn parse_arguments(path_buf: *const c_char, argv: *const *const c_char)
-> Result<(String, Vec<CString>), Error>
{
let path_string = {
let path_cstring = clone_cstring_safely(path_buf)?;
path_cstring.to_string_lossy().into_owned()
};
let program_cstring = {
let program_osstr= Path::new(&path_string).file_name()
.ok_or_else(|| Error::new(Errno::EINVAL, "Invalid path"))?;
let program_str = program_osstr.to_str()
.ok_or_else(|| Error::new(Errno::EINVAL, "Invalid path"))?;
CString::new(program_str)
.or_else(|_| errno!(EINVAL, "Invalid path"))?
};
let mut args = clone_cstrings_safely(argv)?;
args.insert(0, program_cstring);
Ok((path_string, args))
}
// TODO: make sure do_boot can only be called once
fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> {
util::mpx_util::mpx_enable()?;
let envp = std::vec::Vec::new();
let file_actions = Vec::new();
let parent = &process::IDLE_PROCESS;
process::do_spawn(&path_str, argv, &envp, &file_actions, parent)?;
Ok(())
}
// TODO: make sure do_run() cannot be called after do_boot()
fn do_run() -> Result<i32, Error> {
let exit_status = process::run_task()?;
Ok(exit_status)
}

@ -1,5 +1,5 @@
use super::*;
use util::{new_ring_buf, RingBufReader, RingBufWriter};
use util::ring_buf::{*};
// TODO: Use Waiter and WaitQueue infrastructure to sleep when blocking
@ -13,13 +13,13 @@ pub struct Pipe {
impl Pipe {
pub fn new() -> Result<Pipe, Error> {
let (reader, writer) = new_ring_buf(PIPE_BUF_SIZE);
let mut ring_buf = RingBuf::new(PIPE_BUF_SIZE);
Ok(Pipe {
reader: PipeReader {
inner: SgxMutex::new(reader),
inner: SgxMutex::new(ring_buf.reader),
},
writer: PipeWriter {
inner: SgxMutex::new(writer),
inner: SgxMutex::new(ring_buf.writer),
}
})
}

@ -26,6 +26,7 @@ use sgx_trts::libc;
#[macro_use]
mod prelude;
mod entry;
mod errno;
mod fs;
mod process;
@ -36,58 +37,7 @@ mod time;
use prelude::*;
/// Export system calls
// Export system calls
pub use syscall::*;
// TODO: return meaningful exit code
#[no_mangle]
pub extern "C" fn libos_boot(path_buf: *const i8) -> i32 {
let path_str = unsafe {
CStr::from_ptr(path_buf).to_string_lossy().into_owned()
};
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
panic::catch_unwind(||{
backtrace::__rust_begin_short_backtrace(||{
match do_boot(&path_str) {
Ok(()) => 0,
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
}
})
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
}
#[no_mangle]
pub extern "C" fn libos_run() -> i32 {
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
panic::catch_unwind(||{
backtrace::__rust_begin_short_backtrace(||{
match do_run() {
Ok(exit_status) => exit_status,
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
}
})
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
}
// Use 127 as a special value to indicate internal error from libos, not from
// user programs, although it is completely ok for a user program to return 127.
const EXIT_STATUS_INTERNAL_ERROR : i32 = 127;
// TODO: make sure do_boot can only be called once
fn do_boot(path_str: &str) -> Result<(), Error> {
util::mpx_enable()?;
let argv = std::vec::Vec::new();
let envp = std::vec::Vec::new();
let file_actions = Vec::new();
let parent = &process::IDLE_PROCESS;
process::do_spawn(&path_str, &argv, &envp, &file_actions, parent)?;
Ok(())
}
// TODO: make sure do_run() cannot be called before do_boot()
fn do_run() -> Result<i32, Error> {
let exit_status = process::run_task()?;
Ok(exit_status)
}
// Export ECalls
pub use entry::*;

@ -7,6 +7,7 @@ use fs::{off_t, FileDesc};
use vm::{VMAreaFlags, VMResizeOptions};
use process::{pid_t, ChildProcessFilter, FileAction};
use time::{timeval_t};
use util::mem_util::from_user::{*};
// Use the internal syscall wrappers from sgx_tstd
//use std::libc_fs as fs;
//use std::libc_io as io;
@ -17,39 +18,6 @@ pub struct iovec_t {
len: size_t,
}
fn check_ptr_from_user<T>(user_ptr: *const T) -> Result<(), Error> {
Ok(())
}
fn check_mut_ptr_from_user<T>(user_ptr: *mut T) -> Result<(), Error> {
Ok(())
}
fn check_array_from_user<T>(user_buf: *const T, count: usize) -> Result<(), Error> {
Ok(())
}
fn check_mut_array_from_user<T>(user_buf: *mut T, count: usize) -> Result<(), Error> {
Ok(())
}
fn clone_cstring_from_user_safely(user_ptr: *const c_char)
-> Result<String, Error>
{
check_ptr_from_user(user_ptr)?;
let string = unsafe {
CStr::from_ptr(user_ptr).to_string_lossy().into_owned()
};
Ok(string)
}
fn clone_cstrings_from_user_safely(user_ptr: *const *const c_char)
-> Result<Vec<CString>, Error>
{
let cstrings = Vec::new();
Ok(cstrings)
}
/*
* This Rust-version of fdop correspond to the C-version one in Occlum.
@ -73,14 +41,14 @@ pub struct FdOp {
path: *const u8,
}
fn clone_file_actions_from_user_safely(fdop_ptr: *const FdOp)
fn clone_file_actions_safely(fdop_ptr: *const FdOp)
-> Result<Vec<FileAction>, Error>
{
let mut file_actions = Vec::new();
let mut fdop_ptr = fdop_ptr;
while fdop_ptr != ptr::null() {
check_ptr_from_user(fdop_ptr)?;
check_ptr(fdop_ptr)?;
let fdop = unsafe { &*fdop_ptr };
let file_action = match fdop.cmd {
@ -113,11 +81,11 @@ fn do_spawn(child_pid_ptr: *mut c_uint,
)
-> Result<(), Error>
{
check_mut_ptr_from_user(child_pid_ptr)?;
let path = clone_cstring_from_user_safely(path)?;
let argv = clone_cstrings_from_user_safely(argv)?;
let envp = clone_cstrings_from_user_safely(envp)?;
let file_actions = clone_file_actions_from_user_safely(fdop_list)?;
check_mut_ptr(child_pid_ptr)?;
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let argv = clone_cstrings_safely(argv)?;
let envp = clone_cstrings_safely(envp)?;
let file_actions = clone_file_actions_safely(fdop_list)?;
let parent = process::get_current();
let child_pid = process::do_spawn(&path, &argv, &envp, &file_actions, &parent)?;
@ -133,7 +101,7 @@ fn do_read(fd: c_int, buf: *mut c_void, size: size_t)
let safe_buf = {
let buf = buf as *mut u8;
let size = size as usize;
check_mut_array_from_user(buf, size)?;
check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
fs::do_read(fd, safe_buf)
@ -146,7 +114,7 @@ fn do_write(fd: c_int, buf: *const c_void, size: size_t)
let safe_buf = {
let buf = buf as *mut u8;
let size = size as usize;
check_array_from_user(buf, size)?;
check_array(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) }
};
fs::do_write(fd, safe_buf)
@ -164,7 +132,7 @@ fn do_writev(fd: c_int, iov: *const iovec_t, count: c_int)
count as usize
};
check_array_from_user(iov, count);
check_array(iov, count);
let bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
@ -194,7 +162,7 @@ fn do_readv(fd: c_int, iov: *mut iovec_t, count: c_int)
count as usize
};
check_array_from_user(iov, count);
check_array(iov, count);
let mut bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
@ -274,7 +242,7 @@ fn do_brk(new_brk_addr: *const c_void) -> Result<*const c_void, Error> {
fn do_wait4(pid: c_int, _exit_status: *mut c_int) -> Result<pid_t, Error> {
if _exit_status != 0 as *mut c_int {
check_mut_ptr_from_user(_exit_status)?;
check_mut_ptr(_exit_status)?;
}
let child_process_filter = match pid {
@ -310,7 +278,7 @@ fn do_wait4(pid: c_int, _exit_status: *mut c_int) -> Result<pid_t, Error> {
}
fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> {
check_mut_array_from_user(fds_u, 2)?;
check_mut_array(fds_u, 2)?;
// TODO: how to deal with open flags???
let fds = fs::do_pipe2(flags as u32)?;
unsafe {
@ -321,7 +289,7 @@ fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> {
}
fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<(), Error> {
check_mut_ptr_from_user(tv_u)?;
check_mut_ptr(tv_u)?;
let tv = time::do_gettimeofday();
unsafe { *tv_u = tv; }
Ok(())

@ -0,0 +1,110 @@
use super::*;
use std::ffi::{CStr, CString};
use std::{ptr};
/// Memory utilities that deals with primitive types passed from user process
/// running inside enclave
pub mod from_user {
use super::*;
/// Check the user pointer is within the readable memory range of the user process
pub fn check_ptr<T>(user_ptr: *const T) -> Result<(), Error> {
Ok(())
}
/// Check the mutable user pointer is within the writable memory of the user process
pub fn check_mut_ptr<T>(user_ptr: *mut T) -> Result<(), Error> {
Ok(())
}
/// Check the readonly array is within the readable memory of the user process
pub fn check_array<T>(user_buf: *const T, count: usize) -> Result<(), Error> {
Ok(())
}
/// Check the mutable array is within the writable memory of the user process
pub fn check_mut_array<T>(user_buf: *mut T, count: usize) -> Result<(), Error> {
Ok(())
}
/// Clone a C-string from the user process safely
pub fn clone_cstring_safely(out_ptr: *const c_char)
-> Result<CString, Error>
{
check_ptr(out_ptr)?;
// TODO: using from_ptr directly is not safe
let cstr = unsafe { CStr::from_ptr(out_ptr) };
let cstring = CString::from(cstr);
Ok(cstring)
}
/// Clone a C-string array (const char*[]) from the user process safely
///
/// This array must be ended with a NULL pointer.
pub fn clone_cstrings_safely(user_ptr: *const *const c_char)
-> Result<Vec<CString>, Error>
{
let mut cstrings = Vec::new();
let mut user_ptr = user_ptr;
while user_ptr != ptr::null() {
let cstr_ptr = unsafe { *user_ptr };
let cstring = clone_cstring_safely(cstr_ptr)?;
cstrings.push(cstring);
user_ptr = unsafe { user_ptr.offset(1) };
}
Ok(cstrings)
}
}
/// Memory utilities that deals with primitive types passed from outside the enclave
pub mod from_untrusted {
use super::*;
/// Check the untrusted pointer is outside the enclave
pub fn check_ptr<T>(out_ptr: *const T) -> Result<(), Error> {
Ok(())
}
/// Check the untrusted array is outside the enclave
pub fn check_array<T>(out_ptr: *const T, count: usize) -> Result<(), Error> {
Ok(())
}
/// Clone a C-string from outside the enclave
pub fn clone_cstring_safely(out_ptr: *const c_char)
-> Result<CString, Error>
{
check_ptr(out_ptr)?;
// TODO: using from_ptr directly is not safe
let cstr = unsafe { CStr::from_ptr(out_ptr) };
let cstring = CString::from(cstr);
Ok(cstring)
}
/// Clone a C-string array (const char*[]) from outside the enclave
///
/// This array must be ended with a NULL pointer.
pub fn clone_cstrings_safely(out_ptr: *const *const c_char)
-> Result<Vec<CString>, Error>
{
let mut cstrings = Vec::new();
if out_ptr == ptr::null() { return Ok(cstrings); }
let mut out_ptr = out_ptr;
loop {
check_ptr(out_ptr);
let cstr_ptr = {
let cstr_ptr = unsafe { *out_ptr };
if cstr_ptr == ptr::null() { break; }
check_ptr(cstr_ptr);
cstr_ptr
};
let cstring = clone_cstring_safely(cstr_ptr)?;
cstrings.push(cstring);
out_ptr = unsafe { out_ptr.offset(1) };
}
Ok(cstrings)
}
}

@ -1,8 +1,5 @@
use super::*;
pub use self::mpx_util::{*};
pub use self::ring_buf::{RingBufReader, RingBufWriter};
pub use self::ring_buf::with_fixed_capacity as new_ring_buf;
mod mpx_util;
mod ring_buf;
pub mod mpx_util;
pub mod ring_buf;
pub mod mem_util;

@ -4,11 +4,19 @@ use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::cmp::{min, max};
use std::{ptr};
pub fn with_fixed_capacity(capacity: usize) -> (RingBufReader, RingBufWriter) {
#[derive(Debug)]
pub struct RingBuf {
pub reader: RingBufReader,
pub writer: RingBufWriter,
}
impl RingBuf {
pub fn new(capacity: usize) -> RingBuf {
let inner = Arc::new(RingBufInner::new(capacity));
let reader = RingBufReader { inner: inner.clone() };
let writer = RingBufWriter { inner: inner };
(reader, writer)
RingBuf { reader: reader, writer: writer }
}
}
#[derive(Debug)]

@ -214,9 +214,9 @@ int SGX_CDECL main(int argc, char *argv[])
uint32_t sealed_log_size = 1024;
uint8_t sealed_log[1024] = {0};
if (argc != 2) {
printf("ERROR: The expected number of arguments is 1, but given %d\n\n", argc - 1);
printf("Usage: pal <path_to_executable>\n");
if (argc < 2) {
printf("ERROR: at least one argument must be provided\n\n");
printf("Usage: pal <executable> <arg1> <arg2>...\n");
return -1;
}
const char* executable_path = argv[1];
@ -229,7 +229,7 @@ int SGX_CDECL main(int argc, char *argv[])
return -1;
}
sgx_ret = libos_boot(global_eid, &status, executable_path);
sgx_ret = libos_boot(global_eid, &status, executable_path, &argv[2]);
if(sgx_ret != SGX_SUCCESS) {
print_error_message(sgx_ret);
return status;

@ -1,7 +1,7 @@
CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
PROJECT_DIR := $(realpath $(CUR_DIR)/../)
TEST_SUITES := empty hello_world malloc file getpid spawn pipe time
TEST_SUITES := empty argv hello_world malloc file getpid spawn pipe time
BUILD_TEST_SUITES := $(TEST_SUITES:%=%)
RUN_TEST_SUITES := $(TEST_SUITES:%=test-%)
CLEAN_TEST_SUITES := $(TEST_SUITES:%=clean-%)

14
test/argv/Makefile Normal file

@ -0,0 +1,14 @@
include ../test_common.mk
ARGC := 4
ARG1 := 1
ARG2 := arg2
ARG3 := this is a string with spaces
EXTRA_C_FLAGS := \
-DEXPECTED_ARGC=$(ARGC) \
-DEXPECTED_ARG1="\"$(ARG1)\"" \
-DEXPECTED_ARG2="\"$(ARG2)\"" \
-DEXPECTED_ARG3="\"$(ARG3)\""
EXTRA_LINK_FLAGS :=
BIN_ARGS := "$(ARG1)" "$(ARG2)" "$(ARG3)"

30
test/argv/main.c Normal file

@ -0,0 +1,30 @@
#include <string.h>
#include <stdio.h>
// Expected arguments are given by Makefile throught macro ARGC, ARG1, ARG2 and
// ARG3
const char* expected_argv[EXPECTED_ARGC] = {
"bin.encrypted",
EXPECTED_ARG1,
EXPECTED_ARG2,
EXPECTED_ARG3,
};
int main(int argc, char* argv[]) {
if (argc != EXPECTED_ARGC) {
printf("ERROR: expect %d arguments, but %d are given\n", EXPECTED_ARGC, argc);
return -1;
}
for (int arg_i = 0; arg_i < argc; arg_i++) {
const char* actual_arg = argv[arg_i];
const char* expected_arg = expected_argv[arg_i];
if (strcmp(actual_arg, expected_arg) != 0) {
printf("ERROR: expect argument %d is %s, but given %s\n",
arg_i, expected_arg, actual_arg);
}
}
printf("main()'s argc and argv are as expected\n");
return 0;
}

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

@ -56,7 +56,7 @@ $(C_OBJS): %.o: %.c
#############################################################################
test: $(BIN_ENC_NAME)
@cd ../ && RUST_BACKTRACE=1 ./pal $(CUR_DIR)/$(BIN_ENC_NAME)
@cd ../ && RUST_BACKTRACE=1 ./pal $(CUR_DIR)/$(BIN_ENC_NAME) $(BIN_ARGS)
#############################################################################
# Misc

@ -2,3 +2,4 @@ include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=