diff --git a/.gitmodules b/.gitmodules index 60201c92..158c4558 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,7 @@ [submodule "deps/rust-sgx-sdk"] path = deps/rust-sgx-sdk url = https://github.com/baidu/rust-sgx-sdk - branch = rust-stable + branch = master +[submodule "deps/sgx_protect_file"] + path = deps/sgx_protect_file + url = https://github.com/tatetian/sgx_protect_file diff --git a/Makefile b/Makefile index e339551a..61a06384 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ all: build_src build_test init: git submodule init git submodule update - cd deps/rust-sgx-sdk && git apply ../rust-sgx-sdk.patch + #cd deps/rust-sgx-sdk && git apply ../rust-sgx-sdk.patch + cd deps/sgx_protect_file && make build_src: @$(MAKE) --no-print-directory -C src diff --git a/README.md b/README.md index c503b5c1..edb30a61 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Rusgx is a single-address-space library OS for Intel SGX. It is written in Rust ### Prerequisite -Rusgx depends on [Rust SGX SDK](https://github.com/baidu/rust-sgx-sdk/). So, make sure Rust SGX SDk can be built properly. We have tested with Rust SGX SDK 1.0, Rust 1.26.0 and Intel SGX SDK 2.1 on Ubuntu 16.04. +Rusgx depends on [Rust SGX SDK](https://github.com/baidu/rust-sgx-sdk/). So, make sure Rust SGX SDk can be built properly. We have tested with Rust SGX SDK 1.1, Rust nightly-2018-08-25 and Intel SGX SDK 2.2 on Ubuntu 16.04. ### Compile diff --git a/deps/rust-sgx-sdk b/deps/rust-sgx-sdk index 32fa6b14..f26dcd8f 160000 --- a/deps/rust-sgx-sdk +++ b/deps/rust-sgx-sdk @@ -1 +1 @@ -Subproject commit 32fa6b14326fcf8390891a4c5c86b755fc29d24f +Subproject commit f26dcd8f5fce88780c83a7c54b774e6e9d36aa23 diff --git a/deps/rust-sgx-sdk.patch b/deps/rust-sgx-sdk.patch deleted file mode 100644 index f5b108ec..00000000 --- a/deps/rust-sgx-sdk.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/sgx_tstd/src/lib.rs b/sgx_tstd/src/lib.rs -index 33ee1f2..7f3dab8 100644 ---- a/sgx_tstd/src/lib.rs -+++ b/sgx_tstd/src/lib.rs -@@ -222,6 +222,11 @@ pub mod untrusted; - mod sys_common; - mod sys; - -+// @tatetian -+// Export some internals of sys so that libos can use them directly -+pub use sys::fs::libc as libc_fs; -+pub use sys::fd::libc as libc_io; -+ - // Private support modules - mod panicking; - mod cpuid; -diff --git a/sgx_tstd/src/sys/fd.rs b/sgx_tstd/src/sys/fd.rs -index 3fa46d9..28daa9b 100644 ---- a/sgx_tstd/src/sys/fd.rs -+++ b/sgx_tstd/src/sys/fd.rs -@@ -209,7 +209,9 @@ impl Drop for FileDesc { - } - } - --mod libc { -+// @tatetian -+// Make this public so that the libos can use it directly -+pub mod libc { - use sgx_types::sgx_status_t; - use io; - pub use sgx_trts::libc::*; -diff --git a/sgx_tstd/src/sys/fs.rs b/sgx_tstd/src/sys/fs.rs -index a611f39..cc54c31 100644 ---- a/sgx_tstd/src/sys/fs.rs -+++ b/sgx_tstd/src/sys/fs.rs -@@ -455,7 +455,9 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { - Ok(ret) - } - --mod libc { -+// @tatetian -+// Make this public so that the libos can use it directly -+pub mod libc { - use sgx_types::sgx_status_t; - use io; - use core::ptr; diff --git a/deps/sgx_protect_file b/deps/sgx_protect_file new file mode 160000 index 00000000..3c9a9f06 --- /dev/null +++ b/deps/sgx_protect_file @@ -0,0 +1 @@ +Subproject commit 3c9a9f063dacf5ef98971e64338d315e107a9083 diff --git a/src/Enclave.edl b/src/Enclave.edl index 922d1cdf..8bbb87df 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -5,13 +5,15 @@ enclave { from "sgx_tstd.edl" import *; from "sgx_net.edl" import *; from "sgx_time.edl" import *; + from "sgx_tprotected_fs.edl" import *; trusted { /* define ECALLs here. */ - public int libos_boot(void); + public int libos_boot([in, string] const char* executable_path); + public int libos_run(void); }; untrusted { - + void ocall_print_string([in, string] const char* msg); }; }; diff --git a/src/libos/Cargo.lock b/src/libos/Cargo.lock index 74ea6590..488ccb36 100644 --- a/src/libos/Cargo.lock +++ b/src/libos/Cargo.lock @@ -1,16 +1,28 @@ [[package]] name = "Rusgx" -version = "1.0.0" +version = "0.0.1" dependencies = [ - "sgx_tstd 1.0.0", - "sgx_types 1.0.0", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sgx_trts 1.0.1", + "sgx_tstd 1.0.1", + "sgx_types 1.0.1", + "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sgx_alloc" -version = "1.0.0" +version = "1.0.1" dependencies = [ - "sgx_trts 1.0.0", + "sgx_trts 1.0.1", ] [[package]] @@ -19,39 +31,68 @@ version = "0.1.0" [[package]] name = "sgx_tprotected_fs" -version = "1.0.0" +version = "1.0.1" dependencies = [ - "sgx_trts 1.0.0", - "sgx_types 1.0.0", + "sgx_trts 1.0.1", + "sgx_types 1.0.1", ] [[package]] name = "sgx_trts" -version = "1.0.0" +version = "1.0.1" dependencies = [ - "sgx_types 1.0.0", + "sgx_types 1.0.1", ] [[package]] name = "sgx_tstd" -version = "1.0.0" +version = "1.0.1" dependencies = [ - "sgx_alloc 1.0.0", + "sgx_alloc 1.0.1", "sgx_build_helper 0.1.0", - "sgx_tprotected_fs 1.0.0", - "sgx_trts 1.0.0", - "sgx_types 1.0.0", - "sgx_unwind 0.0.0", + "sgx_tprotected_fs 1.0.1", + "sgx_trts 1.0.1", + "sgx_types 1.0.1", + "sgx_unwind 0.0.1", ] [[package]] name = "sgx_types" -version = "1.0.0" +version = "1.0.1" [[package]] name = "sgx_unwind" -version = "0.0.0" +version = "0.0.1" dependencies = [ - "sgx_trts 1.0.0", + "sgx_trts 1.0.1", ] +[[package]] +name = "spin" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "xmas-elf" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zero" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" +"checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4" +"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" +"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" +"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/src/libos/Cargo.toml b/src/libos/Cargo.toml index 9ce17420..b21ec54f 100644 --- a/src/libos/Cargo.toml +++ b/src/libos/Cargo.toml @@ -1,14 +1,19 @@ [package] name = "Rusgx" -version = "1.0.0" +version = "0.0.1" [lib] -name = "rusgx" +name = "libos" crate-type = ["staticlib"] +[dependencies] +xmas-elf = "0.6" +lazy_static = { version = "1.1.0", features = ["spin_no_std"] } # Implies nightly + [features] default = [] [target.'cfg(not(target_env = "sgx"))'.dependencies] sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" } -sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd" } +sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd", features = ["backtrace"] } +sgx_trts = { path = "../../deps/rust-sgx-sdk/sgx_trts" } diff --git a/test/Enclave.lds b/src/libos/Enclave.lds similarity index 100% rename from test/Enclave.lds rename to src/libos/Enclave.lds diff --git a/test/Enclave_config.xml b/src/libos/Enclave_config.xml similarity index 100% rename from test/Enclave_config.xml rename to src/libos/Enclave_config.xml diff --git a/test/Enclave_private.pem b/src/libos/Enclave_private.pem similarity index 100% rename from test/Enclave_private.pem rename to src/libos/Enclave_private.pem diff --git a/src/libos/Makefile b/src/libos/Makefile index c1044a9b..884bc5f5 100644 --- a/src/libos/Makefile +++ b/src/libos/Makefile @@ -1,14 +1,63 @@ -LIB_NAME := librusgx.a -SRCS := $(wildcard src/*.rs) +include ../sgxenv.mk -.PHONY: all clean +DEBUG=1 -all: $(LIB_NAME) +LIBOS_ENCLAVE := librusgx.signed.so +LIBOS_SO := librusgx.so # Link $(LIBOS_A), $(C_OBJS) and all dependencies +LIBOS_A := liblibos.a # Built from Rust code -$(LIB_NAME): $(SRCS) +RUST_SRCS := $(wildcard src/*.rs) +C_SRCS := $(sort $(filter-out src/Enclave_t.c, $(wildcard src/*.c))) src/Enclave_t.c +C_OBJS := $(C_SRCS:.c=.o) +S_SRCS := $(wildcard src/*.S) +S_OBJS := $(S_SRCS:.S=.o) +EDL_C_SRCS := src/Enclave_t.c src/Enclave_t.h + +ENCLAVE_CONFIG := Enclave_config.xml +ENCLAVE_KEY := Enclave_private.pem + +C_FLAGS := $(SGX_CFLAGS_T) -fno-stack-protector +_Other_Link_Flags := -L../../deps/rust-sgx-sdk/compiler-rt/ -L. +_Other_Enclave_Libs := -lcompiler-rt-patch -llibos -lsgx_tprotected_fs +LINK_FLAGS := $(SGX_LFLAGS_T) + +.PHONY: all compiler-rt clean + +all: $(LIBOS_ENCLAVE) + +$(LIBOS_ENCLAVE): $(LIBOS_SO) + @$(SGX_ENCLAVE_SIGNER) sign -key $(ENCLAVE_KEY) -enclave $^ -out $@ -config $(ENCLAVE_CONFIG) + @echo "SIGN => $@" + +$(LIBOS_SO): compiler-rt $(LIBOS_A) $(C_OBJS) $(S_OBJS) + @$(CC) $(C_OBJS) $(S_OBJS) -o $@ $(LINK_FLAGS) + @echo "LINK => $@" + +$(C_OBJS): %.o: %.c + @$(CC) $(C_FLAGS) -c $< -o $@ + @echo "CC <= $@" + +$(S_OBJS): %.o: %.S + @$(CC) $(C_FLAGS) -c $< -o $@ + @echo "CC <= $@" + +$(EDL_C_SRCS): $(SGX_EDGER8R) ../Enclave.edl + @cd src/ && $(SGX_EDGER8R) --trusted ../../Enclave.edl --search-path $(SGX_SDK)/include --search-path ../../../deps/rust-sgx-sdk/edl/ + @echo "GEN => $(EDL_C_SRCS)" + +compiler-rt: + @$(MAKE) --no-print-directory -C ../../deps/rust-sgx-sdk/compiler-rt/ 2> /dev/null + +ifeq ($(DEBUG), 1) +$(LIBOS_A): $(RUST_SRCS) + RUSTC_BOOTSTRAP=1 cargo build + cp ./target/debug/$(LIBOS_A) $(LIBOS_A) +else +$(LIBOS_A): $(RUST_SRCS) RUSTC_BOOTSTRAP=1 cargo build --release - cp ./target/release/$(LIB_NAME) $(LIB_NAME) + cp ./target/release/$(LIBOS_A) $(LIBOS_A) +endif clean: @cargo clean - @-$(RM) $(LIB_NAME) + @-$(RM) $(LIBOS_ENCLAVE) $(LIBOS_SO) $(LIBOS_A) $(C_OBJS) $(S_OBJS) $(EDL_C_SRCS) diff --git a/src/libos/src/elf_helper.rs b/src/libos/src/elf_helper.rs new file mode 100644 index 00000000..efdda0f2 --- /dev/null +++ b/src/libos/src/elf_helper.rs @@ -0,0 +1,126 @@ +use xmas_elf::{ElfFile, program, P64}; +use xmas_elf::sections; +use xmas_elf::symbol_table::{Entry64, DynEntry64}; +use xmas_elf::program::{ProgramHeader}; +use xmas_elf::sections::{Rela}; +use xmas_elf::symbol_table::Entry; + +pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), &'static str> { + println!("Program headers:"); + let ph_iter = elf_file.program_iter(); + for sect in ph_iter { + program::sanity_check(sect, &elf_file)?; + println!("\t{:?}", sect.get_type()); + } + Ok(()) +} + +pub fn print_sections(elf_file: &ElfFile) -> Result<(), &'static str> { + println!("Sections:"); + let mut sect_iter = elf_file.section_iter(); + sect_iter.next(); // Skip the first, dummy section + for sect in sect_iter { + sections::sanity_check(sect, &elf_file)?; + println!("\t{}\n{:?}", sect.get_name(&elf_file)?, sect); + } + Ok(()) +} + +pub fn print_pltrel_section(elf_file: &ElfFile) -> Result<(), &'static str> { + let rela_entries = get_pltrel_entries(elf_file)?; + let dynsym_entries = get_dynsym_entries(elf_file)?; + + println!(".plt.rela section:"); + for entry in rela_entries { + println!("\toffset: {}, symbol index: {}, type: {}, addend: {}", + entry.get_offset(), + entry.get_symbol_table_index(), + entry.get_type(), + entry.get_addend()); + + let symidx = entry.get_symbol_table_index() as usize; + let dynsym_entry = &dynsym_entries[symidx]; + println!("\t\t{} = {:?}", + dynsym_entry.get_name(&elf_file)?, dynsym_entry); + } + Ok(()) +} + +pub fn get_data_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) + -> Result, &'static str> +{ + let mut ph_iter = elf_file.program_iter(); + ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) && + !ph.flags().is_execute() && + ph.flags().is_write() && + ph.flags().is_read()) + .ok_or("Cannot find .data in the program header of ELF") +} + +pub fn get_code_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) + -> Result, &'static str> +{ + let mut ph_iter = elf_file.program_iter(); + ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) && + ph.flags().is_execute() && + !ph.flags().is_write() && + ph.flags().is_read()) + .ok_or("Cannot find .text in the program header of ELF") +} + +pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) + -> Result +{ + let sym_entries = get_sym_entries(elf_file)?; + + for sym_entry in sym_entries { + let sym_str = sym_entry.get_name(elf_file)?; + if sym_str == "_start" { + return Ok(sym_entry.value() as usize) + } + } + + Err("Cannot find _start symbol") +} + +pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) + -> Result<&'a [Entry64], &'static str> +{ + elf_file.find_section_by_name(".symtab") + .and_then(|symtab_section| { + symtab_section.get_data(&elf_file).ok() + }).and_then(|symbol_table| { + match symbol_table { + sections::SectionData::SymbolTable64(entries) => Some(entries), + _ => None, + } + }).ok_or("Cannot find or load .dynsym section") +} + +pub fn get_pltrel_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) + -> Result<&'a [Rela], &'static str> +{ + elf_file.find_section_by_name(".rela.plt") + .and_then(|plt_rela_section| { + plt_rela_section.get_data(&elf_file).ok() + }).and_then(|rela_table| { + match rela_table { + sections::SectionData::Rela64(entries) => Some(entries), + _ => None, + } + }).ok_or("Cannot find or load .rela.plt section") +} + +pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) + -> Result<&'a [DynEntry64], &'static str> +{ + elf_file.find_section_by_name(".dynsym") + .and_then(|dynamic_section| { + dynamic_section.get_data(&elf_file).ok() + }).and_then(|dynamic_table| { + match dynamic_table { + sections::SectionData::DynSymbolTable64(entries) => Some(entries), + _ => None, + } + }).ok_or("Cannot find or load .dynsym section") +} diff --git a/src/libos/src/lib.rs b/src/libos/src/lib.rs index a1cf6893..6af1e5e5 100644 --- a/src/libos/src/lib.rs +++ b/src/libos/src/lib.rs @@ -1,24 +1,67 @@ -#![crate_name = "rusgx"] +#![allow(unused)] + +#![crate_name = "libos"] #![crate_type = "staticlib"] #![cfg_attr(not(target_env = "sgx"), no_std)] #![cfg_attr(target_env = "sgx", feature(rustc_private))] +#![feature(allocator_api)] +#![feature(integer_atomics)] extern crate sgx_types; #[cfg(not(target_env = "sgx"))] #[macro_use] extern crate sgx_tstd as std; -use sgx_types::*; +extern crate sgx_trts; +extern crate xmas_elf; +#[macro_use] +extern crate lazy_static; -extern "C" { - pub fn main() -> c_int; +use std::ffi::CStr; // a borrowed C string +use std::backtrace::{self, PrintFormat}; +use std::panic; + +use sgx_types::*; +use sgx_trts::libc; + +mod vma; +mod process; +mod syscall; +mod elf_helper; +mod mm; + +use process::spawn_process; +use process::run_task; + +/// Export system calls +pub use syscall::{rusgx_write}; + +#[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() + }; + println!("LibOS boots: {}", path_str); + + let _ = backtrace::enable_backtrace("librusgx.signed.so", PrintFormat::Short); + panic::catch_unwind(||{ + backtrace::__rust_begin_short_backtrace(||{ + let _ = spawn_process(&path_str); + }) + }).ok(); + + 0 } #[no_mangle] -pub extern "C" fn libos_boot() -> sgx_status_t { - println!("{}", "LibOS boots"); - unsafe { main(); } - sgx_status_t::SGX_SUCCESS +pub extern "C" fn libos_run() -> i32 { + let _ = backtrace::enable_backtrace("librusgx.signed.so", PrintFormat::Short); + panic::catch_unwind(||{ + backtrace::__rust_begin_short_backtrace(||{ + let _ = run_task(); + }) + }).ok(); + + 0 } -pub mod syscall; diff --git a/src/libos/src/mm.rs b/src/libos/src/mm.rs new file mode 100644 index 00000000..173efb18 --- /dev/null +++ b/src/libos/src/mm.rs @@ -0,0 +1,84 @@ +use sgx_types::{c_void, c_int, size_t}; +use sgx_trts::libc; +use std::mem; +use std::marker::Send; +use std::marker::Sync; + +#[derive(Clone, Debug)] +pub struct MemObj { + mem_ptr: *mut c_void, + mem_size: usize, + mem_align: usize, +} + +impl MemObj { + pub fn new(mem_size: usize, mem_align: usize) + -> Result + { + if mem_size == 0 || !is_power_of_two(mem_align) || + mem_align % mem::size_of::<*const c_void>() != 0 { + return Err("Invalid argument"); + } + + let mem_ptr = unsafe { aligned_malloc(mem_size, mem_align) }; + if mem_ptr == (0 as *mut c_void) { + return Err("Out of memory"); + }; + unsafe { memset(mem_ptr, 0 as c_int, mem_size as size_t) }; + + Ok(MemObj { + mem_ptr: mem_ptr, + mem_size: mem_size, + mem_align: mem_align, + }) + } + + pub fn get_addr(&self) -> usize { + self.mem_ptr as usize + } +} + +impl Default for MemObj { + fn default() -> Self { + MemObj { + mem_ptr: 0 as *mut c_void, + mem_size: 0, + mem_align: 1 + } + } +} + +impl Drop for MemObj { + fn drop(&mut self) { + if self.mem_ptr != (0 as *mut c_void) { + unsafe { free(self.mem_ptr); } + } + } +} + +unsafe impl Send for MemObj {} +unsafe impl Sync for MemObj {} + + +fn is_power_of_two(x: usize) -> bool { + return (x != 0) && ((x & (x - 1)) == 0); +} + +unsafe fn aligned_malloc(mem_size: usize, mem_align: usize) -> *mut c_void { + let mut mem_ptr = ::core::ptr::null_mut(); + let ret = libc::posix_memalign(&mut mem_ptr, mem_align, mem_size); + if ret == 0 { + mem_ptr + } else { + 0 as *mut c_void + } +} + +unsafe fn free(mem_ptr: *mut c_void) { + libc::free(mem_ptr) +} + +#[link(name = "sgx_tstdc")] +extern { + pub fn memset(p: *mut c_void, c: c_int, n: size_t) -> *mut c_void; +} diff --git a/src/libos/src/process.rs b/src/libos/src/process.rs new file mode 100644 index 00000000..e0218e24 --- /dev/null +++ b/src/libos/src/process.rs @@ -0,0 +1,182 @@ +use std; +use std::vec::Vec; +use std::path::Path; +use std::sgxfs::SgxFile; +use std::io; +use std::io::{Read}; + +use sgx_types::*; + +use xmas_elf::{ElfFile, header, program}; +use xmas_elf::sections; +use xmas_elf::symbol_table::Entry; + +use {elf_helper, vma, syscall}; +use vma::Vma; +use std::sync::atomic::AtomicU32; +use std::sync::SgxMutex; +use std::sync::Arc; +use std::collections::{HashMap, VecDeque}; + +//static next_pid : AtomicU32 = AtomicU32::new(42); + +lazy_static! { + static ref process_table: SgxMutex>>> = { + SgxMutex::new(HashMap::new()) + }; +} + +pub fn spawn_process>(elf_path: &P) -> Result<(), &'static str> { + let elf_buf = open_elf(elf_path).unwrap(); + let elf_file = ElfFile::new(&elf_buf).unwrap(); + header::sanity_check(&elf_file).unwrap(); +/* + elf_helper::print_program_headers(&elf_file)?; + elf_helper::print_sections(&elf_file)?; + elf_helper::print_pltrel_section(&elf_file)?; +*/ + let new_process = Process::new(&elf_file)?; + println!("new_process: {:#x?}", &new_process); + let new_task = Task::from(&new_process); + + process_table.lock().unwrap() + .insert(0, Arc::new(SgxMutex::new(new_process))); + new_task_queue.lock().unwrap() + .push_back(new_task); + + Ok(()) +} + +pub fn run_task() -> Result<(), &'static str> { + if let Some(new_task) = new_task_queue.lock().unwrap().pop_front() { + println!("Run task: {:#x?}", &new_task); + println!("do_run_task() begin: {}", do_run_task as *const () as usize); + unsafe { do_run_task(&new_task as *const Task); } + println!("do_run_task() end"); + } + Ok(()) +} + +fn open_elf>(path: &P) -> io::Result> { + let key : sgx_key_128bit_t = [0 as uint8_t; 16]; + let mut elf_file = SgxFile::open_ex(path, &key)?; + + let mut elf_buf = Vec::::new(); + elf_file.read_to_end(&mut elf_buf); + Ok(elf_buf) +} + + +#[derive(Clone, Debug, Default)] +#[repr(C)] +pub struct Process { + pub code_vma: Vma, + pub data_vma: Vma, + pub stack_vma: Vma, + pub program_base_addr: usize, + pub program_entry_addr: usize, +} + +impl Process { + pub fn new(elf_file: &ElfFile) -> Result { + let mut new_process : Process = Default::default(); + new_process.create_process_image(elf_file)?; + new_process.link_syscalls(elf_file)?; + new_process.mprotect()?; + Ok(new_process) + } + + fn create_process_image(self: &mut Process, elf_file: &ElfFile) + -> Result<(), &'static str> + { + let code_ph = elf_helper::get_code_program_header(elf_file)?; + let data_ph = elf_helper::get_data_program_header(elf_file)?; + + self.code_vma = Vma::from_program_header(&code_ph)?; + self.data_vma = Vma::from_program_header(&data_ph)?; + self.stack_vma = Vma::new(8 * 1024, 4096, + vma::Perms(vma::PERM_R | vma::PERM_W))?; + + self.program_base_addr = self.alloc_mem_for_vmas(elf_file)?; + self.program_entry_addr = self.program_base_addr + + elf_helper::get_start_address(elf_file)?; + if !self.code_vma.contains(self.program_entry_addr) { + return Err("Entry address is out of the code segment"); + } + + Ok(()) + } + + fn alloc_mem_for_vmas(self: &mut Process, elf_file: &ElfFile) + -> Result + { + let mut vma_list = vec![&mut self.code_vma, &mut self.data_vma, &mut self.stack_vma]; + let base_addr = vma::malloc_batch(&mut vma_list, elf_file.input)?; + + Ok(base_addr) + } + + fn link_syscalls(self: &mut Process, elf_file: &ElfFile) + -> Result<(), &'static str> + { + let syscall_addr = rusgx_syscall as *const () as usize; + + let rela_entries = elf_helper::get_pltrel_entries(&elf_file)?; + let dynsym_entries = elf_helper::get_dynsym_entries(&elf_file)?; + for rela_entry in rela_entries { + let dynsym_idx = rela_entry.get_symbol_table_index() as usize; + let dynsym_entry = &dynsym_entries[dynsym_idx]; + let dynsym_str = dynsym_entry.get_name(&elf_file)?; + + if dynsym_str == "rusgx_syscall" { + let rela_addr = self.program_base_addr + rela_entry.get_offset() as usize; + unsafe { + std::ptr::write_unaligned(rela_addr as *mut usize, syscall_addr); + } + } + } + + Ok(()) + } + + fn mprotect(self: &mut Process) -> Result<(), &'static str> { + let vma_list = vec![&self.code_vma, &self.data_vma, &self.stack_vma]; + vma::mprotect_batch(&vma_list) + } +} + + +#[derive(Clone, Debug, Default)] +#[repr(C)] +pub struct Task { + pub pid: u32, + pub exit_code: u32, + pub syscall_stack_addr: usize, + pub user_stack_addr: usize, + pub user_entry_addr: usize, + pub fs_base_addr: usize, + pub saved_state: usize, // struct jmpbuf* +} + +impl<'a> From<&'a Process> for Task { + fn from(process: &'a Process) -> Task { + Task { + pid: 1234, + user_stack_addr: process.stack_vma.mem_end - 16, + user_entry_addr: process.program_entry_addr, + fs_base_addr: 0, + .. Default::default() + } + } +} + +lazy_static! { + static ref new_task_queue: Arc>> = { + Arc::new(SgxMutex::new(VecDeque::new())) + }; +} + +extern { + fn do_run_task(task: *const Task) -> i32; + fn rusgx_syscall(num: i32, arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> i64; +} diff --git a/src/libos/src/syscall.h b/src/libos/src/syscall.h new file mode 100644 index 00000000..2e498591 --- /dev/null +++ b/src/libos/src/syscall.h @@ -0,0 +1,19 @@ +#ifndef __RUSGX_SYSCALL_H__ +#define __RUSGX_SYSCALL_H__ + +#include + +#define SYS_exit 60 +#define SYS_write 1 + +#ifdef __cplusplus +extern "C" { +#endif + +extern ssize_t rusgx_write(int fd, const void* buf, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* __RUSGX_SYSCALL_H__ */ diff --git a/src/libos/src/syscall.rs b/src/libos/src/syscall.rs index 4265ac6f..1a0ad982 100644 --- a/src/libos/src/syscall.rs +++ b/src/libos/src/syscall.rs @@ -1,10 +1,11 @@ use sgx_types::*; +use std::collections::HashMap; // Use the internal syscall wrappers from sgx_tstd -use std::libc_fs as fs; -use std::libc_io as io; - +//use std::libc_fs as fs; +//use std::libc_io as io; +/* #[no_mangle] pub unsafe extern "C" fn sys_open(path: * const c_char, flags: c_int, mode: c_int) -> c_int { fs::open64(path, flags, mode) @@ -19,8 +20,11 @@ pub unsafe extern "C" fn sys_close(fd: c_int) -> c_int { pub unsafe extern "C" fn sys_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssize_t { io::read(fd, buf, size) } +*/ #[no_mangle] -pub unsafe extern "C" fn sys_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t { - io::write(fd, buf, size) +pub extern fn rusgx_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t { + println!("Hello World!"); + size as ssize_t } + diff --git a/src/libos/src/syscall_entry.c b/src/libos/src/syscall_entry.c new file mode 100644 index 00000000..d89af52e --- /dev/null +++ b/src/libos/src/syscall_entry.c @@ -0,0 +1,20 @@ +#include "syscall.h" +#include "task.h" + +long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg4) { + long ret = 0; + + switch (num) { + case SYS_exit: + do_exit_task((int)arg0); + break; + case SYS_write: + ret = (long) rusgx_write((int)arg0, (const void*)arg1, (size_t)arg2); + break; + default: + ret = -1; + break; + } + + return ret; +} diff --git a/src/libos/src/syscall_entry_x86-64.S b/src/libos/src/syscall_entry_x86-64.S new file mode 100644 index 00000000..be1c3e5a --- /dev/null +++ b/src/libos/src/syscall_entry_x86-64.S @@ -0,0 +1,17 @@ +#define __ASSEMBLY__ +#include "task.h" + + .file "syscall_entry_x86-64.S" + .global rusgx_syscall + .type rusgx_syscall, @function +rusgx_syscall: + push %rbp + movq %rsp, %rbp + + movq %gs:(TD_TASK_OFFSET), %rax + movq TASK_SYSCALL_STACK_OFFSET(%rax), %rsp + call dispatch_syscall + + movq %rbp, %rsp + popq %rbp + ret diff --git a/src/libos/src/task.c b/src/libos/src/task.c new file mode 100644 index 00000000..f94e5ae2 --- /dev/null +++ b/src/libos/src/task.c @@ -0,0 +1,44 @@ +#include "task.h" + +extern void __run_task(uint64_t entry_point, uint64_t stack_top); + +extern uint64_t __get_stack_guard(void); +extern void __set_stack_guard(uint64_t new_val); + +static uint64_t get_syscall_stack(struct Task* this_task) { +#define LARGE_ENOUGH_GAP 4096 + char libos_stack_var = 0; + uint64_t libos_stack = ((uint64_t) &libos_stack_var) - LARGE_ENOUGH_GAP; + libos_stack &= ~0x0FUL; // stack must be 16-byte aligned + return libos_stack; +} + +#define SET_CURRENT_TASK(task) \ + long stack_guard = __get_stack_guard(); \ + __set_current_task(task); + +#define RESET_CURRENT_TASK() \ + __set_stack_guard(stack_guard); + + +int do_run_task(struct Task* task) { + jmp_buf libos_state = {0}; + task->saved_state = &libos_state; + task->syscall_stack_addr = get_syscall_stack(task); + + SET_CURRENT_TASK(task); + + int second = setjmp(libos_state); + if (!second) { + __run_task(task->user_entry_addr, task->user_stack_addr); + } + + // From rusgx_exit + RESET_CURRENT_TASK(); + return task->exit_code; +} + +void do_exit_task(int exitcode) { + jmp_buf* jb = __get_current_task()->saved_state; + longjmp(*jb, 1); +} diff --git a/src/libos/src/task.h b/src/libos/src/task.h new file mode 100644 index 00000000..cc99a594 --- /dev/null +++ b/src/libos/src/task.h @@ -0,0 +1,46 @@ +#ifndef __RUSGX_TASK_H__ +#define __RUSGX_TASK_H__ + +#ifndef __ASSEMBLY__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +// See Struct Task in process.rs +struct Task { + uint32_t pid; + int32_t exit_code; + uint64_t syscall_stack_addr; + uint64_t user_stack_addr; + uint64_t user_entry_addr; + uint64_t fs_base_addr; + jmp_buf* saved_state; +}; + +void __set_current_task(struct Task* task); +struct Task* __get_current_task(void); + +int do_run_task(struct Task* task); +void do_exit_task(int exitcode); + +#ifdef __cplusplus +} +#endif + +#else /* __ASSEMBLY__ */ + +/* See //common/inc/internal/thread_data.h */ +#define TD_STACKGUARD_OFFSET (8 * 5) +/* Override the field for stack guard */ +#define TD_TASK_OFFSET TD_STACKGUARD_OFFSET + +#define TASK_SYSCALL_STACK_OFFSET (8 * 1) + +#endif /* __ASSEMBLY__ */ + +#endif /* __RUSGX_TASK_H__ */ diff --git a/src/libos/src/task_x86-64.S b/src/libos/src/task_x86-64.S new file mode 100644 index 00000000..409f09cd --- /dev/null +++ b/src/libos/src/task_x86-64.S @@ -0,0 +1,34 @@ +#define __ASSEMBLY__ +#include "task.h" + + .file "task_x86-64.S" + + .global __set_current_task + .type __set_current_task, @function +__set_current_task: + movq %rdi, %gs:(TD_TASK_OFFSET) + ret + + .global __get_current_task + .type __get_current_task, @function +__get_current_task: + movq %gs:(TD_TASK_OFFSET), %rax + ret + + .global __get_stack_guard + .type __get_stack_guard, @function +__get_stack_guard: + movq %gs:(TD_TASK_OFFSET), %rax + ret + + .global __set_stack_guard + .type __set_stack_guard, @function +__set_stack_guard: + mov %rdi, %gs:(TD_TASK_OFFSET) + ret + + .global __run_task + .type __run_task, @function +__run_task: + mov %rsi, %rsp + jmp *%rdi diff --git a/src/libos/src/vma.rs b/src/libos/src/vma.rs new file mode 100644 index 00000000..abc3be9a --- /dev/null +++ b/src/libos/src/vma.rs @@ -0,0 +1,192 @@ +/// Virtuam Memory Area (VMA) + +use xmas_elf::program; +use xmas_elf::program::{ProgramHeader}; +use std; +use std::sync::Arc; +use mm::MemObj; +use sgx_types::*; + +#[derive(Clone, Debug, Default)] +#[repr(C)] +pub struct Vma { + /// Basic info + pub mem_size: usize, + pub mem_align: usize, + pub mem_flags: Perms, + + /// File mapping + pub file_is_mapped: bool, + pub mem_addr: usize, + pub file_offset: usize, + pub file_size: usize, + + /// Memory allocation + pub mem_begin: usize, + pub mem_end: usize, + underlying: Arc, +} + +const VMA_MIN_MEM_ALIGN: usize = (4 * 1024); + +impl Vma { + pub fn from_program_header<'a>(ph: &ProgramHeader<'a>) + -> Result + { + let ph64 = match ph { + ProgramHeader::Ph32(ph) => { + return Err("Not support 32-bit ELF") + } + ProgramHeader::Ph64(ph64) => { + ph64 + } + }; + if ph64.align > 1 && ((ph64.offset % ph64.align) != + (ph64.virtual_addr % ph64.align)) { + return Err("Memory address and file offset is not equal, per modulo"); + } + if ph64.mem_size < ph64.file_size { + return Err("Memory size must be greater than file size"); + } + + let mut new_vma = Vma::new(ph64.mem_size as usize, + ph64.align as usize, + Perms::from(&ph64.flags))?; + + new_vma.mem_addr = ph64.virtual_addr as usize; + new_vma.file_is_mapped = true; + new_vma.file_offset = ph64.offset as usize; + new_vma.file_size = ph64.file_size as usize; + + Ok(new_vma) + } + + pub fn new(mem_size: usize, mem_align: usize, mem_flags: Perms) + -> Result + { + if mem_align == 0 || mem_align % VMA_MIN_MEM_ALIGN != 0 { + return Err("Memory alignment is not a multiple of 4KB"); + } + if mem_size == 0 { + return Err("Memory size must be greater than zero"); + } + + Ok(Vma { + mem_size: mem_size, + mem_align: mem_align, + mem_flags: mem_flags, + .. Default::default() + }) + } + + pub fn contains(&self, mem_addr: usize) -> bool { + self.mem_begin <= mem_addr && mem_addr <= self.mem_end + } +} + +pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8]) + -> Result +{ + let mut max_align = VMA_MIN_MEM_ALIGN; + let mut total_size = 0; + for vma in vma_list.into_iter() { + let mem_begin = round_up(total_size, vma.mem_align); + let mem_end = mem_begin + round_up(vma.mem_size, vma.mem_align); + + if vma.file_is_mapped { + if vma.mem_addr < mem_begin || + vma.mem_addr + vma.mem_size > mem_end { + return Err("Impossible memory layout for the VMA"); + } + if vma.file_offset > mapped_data.len() || + vma.file_offset + vma.file_size > mapped_data.len() { + return Err("Impossible to load data from file"); + } + } + + total_size = mem_end; + if vma.mem_align > max_align { + max_align = vma.mem_align; + } + } + + let memobj = Arc::new(MemObj::new(total_size, max_align)?); + let program_base_addr = memobj.get_addr(); + let mut mem_cur = program_base_addr; + for vma in vma_list.into_iter() { + vma.mem_begin = round_up(mem_cur, vma.mem_align); + vma.mem_end = vma.mem_begin + round_up(vma.mem_size, vma.mem_align); + vma.mem_addr += program_base_addr; + vma.underlying = memobj.clone(); + + if vma.file_is_mapped { + let mut vma_data = unsafe { + std::slice::from_raw_parts_mut(vma.mem_addr as *mut u8, vma.file_size) + }; + vma_data.copy_from_slice(&mapped_data[vma.file_offset.. + vma.file_offset + vma.file_size]); + } + + mem_cur = vma.mem_end; + } + + Ok(program_base_addr) +} + +pub fn mprotect_batch(vma_list: &[&Vma]) + -> Result<(), &'static str> +{ + for vma in vma_list.into_iter() { + let start = vma.mem_begin as size_t; + let size = (vma.mem_end - vma.mem_begin) as size_t; + let perms = vma.mem_flags.0 as uint64_t; + let status = unsafe { + trts_mprotect(start, size, perms) + }; + if (status != sgx_status_t::SGX_SUCCESS) { + return Err("trts_mprotect failed"); + } + } + Ok(()) +} + + +#[derive(Copy, Clone, Debug, Default)] +pub struct Perms(pub u32); + +pub const PERM_R: u32 = 0x1; +pub const PERM_W: u32 = 0x2; +pub const PERM_X: u32 = 0x4; + +impl Perms { + pub fn is_execute(&self) -> bool { + self.0 & PERM_X == PERM_X + } + + pub fn is_write(&self) -> bool { + self.0 & PERM_W == PERM_W + } + + pub fn is_read(&self) -> bool { + self.0 & PERM_R == PERM_R + } +} + +impl<'a> From<&'a program::Flags> for Perms { + fn from(flags: &'a program::Flags) -> Self { + let mut val = 0; + if flags.is_execute() { val |= PERM_X; } + if flags.is_read() { val |= PERM_R; } + if flags.is_write() { val |= PERM_W; } + Perms(val) + } +} + +fn round_up(addr: usize, align: usize) -> usize { + (addr + (align - 1)) / align * align +} + +#[link(name = "sgx_trts")] +extern { + pub fn trts_mprotect(start: size_t, size: size_t, perms: uint64_t) -> sgx_status_t; +} diff --git a/src/pal/Makefile b/src/pal/Makefile index 0333d57b..cc191410 100644 --- a/src/pal/Makefile +++ b/src/pal/Makefile @@ -1,4 +1,4 @@ -include ../../buildenv.mk +include ../sgxenv.mk EDL_Gen_Files := Enclave_u.c Enclave_u.h @@ -8,7 +8,7 @@ Bin := pal C_Flags := $(SGX_CFLAGS_U) Link_Flags := $(SGX_LFLAGS_U) -Link_Flags += -L../../deps/rust-sgx-sdk/sgx_ustdc/ -lsgx_ustdc +Link_Flags += -L../../deps/rust-sgx-sdk/sgx_ustdc/ -lsgx_ustdc -lsgx_uprotected_fs all: $(Bin) diff --git a/src/pal/pal.c b/src/pal/pal.c index 1bccff46..d41b8f2c 100644 --- a/src/pal/pal.c +++ b/src/pal/pal.c @@ -187,6 +187,11 @@ int initialize_enclave(const char* enclave_path) return 0; } +// Debug +void ocall_print_string(const char* msg) { + printf("%s", msg); +} + /* Application entry */ int SGX_CDECL main(int argc, char *argv[]) { @@ -197,11 +202,12 @@ int SGX_CDECL main(int argc, char *argv[]) if (argc != 2) { printf("ERROR: The expected number of arguments is 1, but given %d\n\n", argc - 1); - printf("Usage: pal \n"); + printf("Usage: pal \n"); return -1; } - const char* enclave_path = argv[1]; + const char* executable_path = argv[1]; + const char* enclave_path = "librusgx.signed.so"; /* Initialize the enclave */ if(initialize_enclave(enclave_path) < 0){ printf("Enter a character before exit ...\n"); @@ -209,8 +215,13 @@ int SGX_CDECL main(int argc, char *argv[]) return -1; } - sgx_ret = libos_boot(global_eid, &exitcode); + sgx_ret = libos_boot(global_eid, &exitcode, executable_path); + if(sgx_ret != SGX_SUCCESS) { + print_error_message(sgx_ret); + return -1; + } + sgx_ret = libos_run(global_eid, &exitcode); if(sgx_ret != SGX_SUCCESS) { print_error_message(sgx_ret); return -1; diff --git a/buildenv.mk b/src/sgxenv.mk similarity index 61% rename from buildenv.mk rename to src/sgxenv.mk index 6bfd693c..a33a1216 100644 --- a/buildenv.mk +++ b/src/sgxenv.mk @@ -69,11 +69,31 @@ endif # SGX_CFLAGS_T := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector SGX_CFLAGS_T += -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport -I$(SGX_SDK)/include/epid -# Before use this linker flag, the user should define $(Other_Enclave_Libs), -# which lists all libraries that are to be part of the enclave. -SGX_LFLAGS_T = $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) $(Other_Link_Flags) \ +# Before use this linker flag, the user should define $(_Other_Enclave_Libs), +# and $(_Other_Link_Flags) +# +# Linker arguments: +# --no-undefined: Report unresolved symbols. +# --whole-archive --no-whole-archive: Force including all object files +# in the libraries . Normally, only required object files are included +# by the linker. +# --start-group --end-group: Link libraries , resolve any circular +# dependencies between them. +# -Bstatic: Do not link against shared libraries. +# -Bsymbolic: Bind references to global symbols to the definition within this +# shared library. +# -pie: Create a position independent executable +# --defsym==: Define a symbol with the specified value +# --gc-sections: Enable link-time garbage collection, i.e., eliminating unused +# sections. See -ffunction-sections and -fdata-section of GCC. +# +# GCC arguments: +# --nostdlib: Do not use system startup files or libraries when linking. Thus, +# only the libaries that are explictly specified on the command line are +# linked. +SGX_LFLAGS_T = $(SGX_COMMON_CFLAGS) -nostdlib -L$(SGX_LIBRARY_PATH) $(_Other_Link_Flags) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ - -Wl,--start-group -lsgx_tstdc -lsgx_tstdcxx -l$(Crypto_Library_Name) $(Other_Enclave_Libs) -Wl,--end-group \ + -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) $(_Other_Enclave_Libs) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ -Wl,--defsym,__ImageBase=0 \ diff --git a/test/Makefile b/test/Makefile index 345c4647..d16814c7 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,67 +1,19 @@ -include ../buildenv.mk +.PHONY: all build_rusgx_stub build_src clean test -EDL_Gen_Files := Enclave_t.c Enclave_t.h +all: build_rusgx_stub build_src -Enclave_Config := Enclave_config.xml -Enclave_Key := Enclave_private.pem +build_src: build_rusgx_stub + @$(MAKE) -C src -Test_Srcs := $(sort $(filter-out Enclave_t.c, $(wildcard *.c))) -Test_Targets := $(Test_Srcs:%.c=test-%) -Test_Objs := $(Test_Srcs:.c=.o) Enclave_t.o -Test_Enclaves := $(Test_Srcs:.c=.so) -Test_Signed_Enclaves := $(Test_Srcs:.c=.signed.so) +build_rusgx_stub: + @$(MAKE) -C rusgx_stub -C_Flags := $(SGX_CFLAGS_T) +test: all + @$(MAKE) -C src test +test-without-rusgx: all + @$(MAKE) -C src test-without-rusgx -Other_Link_Flags := -L../deps/rust-sgx-sdk/compiler-rt/ -L../src/libos/ -Other_Enclave_Libs := -lcompiler-rt-patch -lrusgx -Link_Flags := $(SGX_LFLAGS_T) - - - -all: build - - - - -.PHONY: build -build: compiler-rt $(Test_Signed_Enclaves) - - -$(Test_Signed_Enclaves): %.signed.so: %.so - @$(SGX_ENCLAVE_SIGNER) sign -key $(Enclave_Key) -enclave $^ -out $@ -config $(Enclave_Config) - @echo "SIGN => $@" - -$(Test_Enclaves): %.so: %.o Enclave_t.o - $(CC) $^ -o $@ $(Link_Flags) - @echo "LINK => $@" - -$(Test_Objs): %.o: %.c - @$(CC) $(C_Flags) -c $< -o $@ - @echo "CC <= $@" - -$(EDL_Gen_Files): $(SGX_EDGER8R) ../src/Enclave.edl - @$(SGX_EDGER8R) --trusted ../src/Enclave.edl --search-path $(SGX_SDK)/include --search-path ../deps/rust-sgx-sdk/edl/ - @echo "GEN => $(EDL_Gen_Files)" - - -.PHONY: compiler-rt -compiler-rt: - @$(MAKE) --no-print-directory -C ../deps/rust-sgx-sdk/compiler-rt/ 2> /dev/null - - -# -# Run tests -# -.PHONY: test -test: $(Test_Targets) - -.PHONY: (Test_Targets) -$(Test_Targets): test-%: %.signed.so - ./../src/pal/pal $^ - - -.PHONY: clean clean: - @-$(RM) $(Test_Signed_Enclaves) $(Test_Enclaves) $(Test_Objs) $(EDL_Gen_Files) + @$(MAKE) -C rusgx_stub clean + @$(MAKE) -C src clean diff --git a/test/empty.c b/test/empty.c deleted file mode 100644 index 33c14ce1..00000000 --- a/test/empty.c +++ /dev/null @@ -1,3 +0,0 @@ -int main() { - return 0; -} diff --git a/test/hello_world.c b/test/hello_world.c deleted file mode 100644 index 68dc65bc..00000000 --- a/test/hello_world.c +++ /dev/null @@ -1,7 +0,0 @@ -extern long long sys_write(int fd, const char* buf, unsigned long long size); - -int main(void) { - char msg[] = "Hello, World!\n"; - sys_write(1, msg, sizeof(msg)); - return 0; -} diff --git a/test/include/rusgx_stub.h b/test/include/rusgx_stub.h new file mode 100644 index 00000000..aaf42721 --- /dev/null +++ b/test/include/rusgx_stub.h @@ -0,0 +1,36 @@ +#ifndef __RUSGX_STUB__ +#define __RUSGX_STUB__ + +#include +#include + +/* + * Stub for Rusgx syscalls + * + * Executables built with Rusgx's toolchain are dynamically linked with this + * stub library. This stub library serves two purposes: + * + * 1) Enable Rusgx's syscalls. Since this library is dynamically linked with + * executables, the compile-time linker generates proper dynamic linking + * information. Using this information, the program loader of Rusgx can do + * runtime relocation so that user programs can make syscalls to the library + * OS. + * + * 2) Run without Rusgx. When not running upon Rusgx, the executables can use the + * host syscalls provided by the default implementation of this library. + */ + +#define SYS_exit 60 +#define SYS_write 1 + +long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg4); + +static inline ssize_t __rusgx_write(int fd, const void* buf, unsigned long size) { + return (ssize_t) rusgx_syscall(SYS_write, (long)fd, (long)buf, (long)size, (long)0, (long)0); +} + +static inline void __rusgx_exit(int status) { + rusgx_syscall(SYS_exit, (long)status, (long)0, (long)0, (long)0, (long)0); +} + +#endif /* __RUSGX_STUB__ */ diff --git a/test/rusgx_stub/Makefile b/test/rusgx_stub/Makefile new file mode 100644 index 00000000..3e5821da --- /dev/null +++ b/test/rusgx_stub/Makefile @@ -0,0 +1,23 @@ +C_SRCS := $(wildcard *.c) +S_FILES := $(C_SRCS:%.c=%.S) +C_OBJS := $(C_SRCS:%.c=%.o) +LIB_NAME := librusgx_stub.so + +C_FLAGS := -Wall -fno-builtin -fno-stack-protector -fverbose-asm -fpic -I../include +C_FLAGS += -O0 +LINK_FLAGS := -nostdlib + +.PHONY: all clean +all: $(LIB_NAME) + +$(LIB_NAME): $(C_OBJS) + $(CC) $^ $(LINK_FLAGS) -shared -o $(LIB_NAME) + +$(C_OBJS): %.o: %.S + $(CC) $(C_FLAGS) -c $< -o $@ + +$(S_FILES): %.S: %.c + $(CC) $(C_FLAGS) -S $< -o $@ + +clean: + $(RM) -f *.o *.S $(LIB_NAME) diff --git a/test/rusgx_stub/stub_impl.c b/test/rusgx_stub/stub_impl.c new file mode 100644 index 00000000..fbc14412 --- /dev/null +++ b/test/rusgx_stub/stub_impl.c @@ -0,0 +1,36 @@ +#include "rusgx_stub.h" + +static long __write(int fd, const void* buf, unsigned long size) { + long ret; + __asm__ __volatile__ ( + "syscall" + : "=a" (ret) + : "0" (SYS_write), "D" (fd), "S" (buf), "d" (size) + : "cc", "rcx", "r11", "memory" + ); + return ret; +} + +static void __exit(int status) { + __asm__ __volatile__ ( + "syscall" + : + : "a" (SYS_exit), "D" (status) + : "cc", "rcx", "r11", "memory" ); + return; +} + +long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg4) { + long ret = 0; + switch (num) { + case SYS_exit: + __exit((int)arg0); + break; + case SYS_write: + ret = __write((int)arg0, (const void*)arg1, (unsigned long)arg2); + break; + default: + break; + } + return ret; +} diff --git a/test/src/Makefile b/test/src/Makefile new file mode 100644 index 00000000..3bb7f439 --- /dev/null +++ b/test/src/Makefile @@ -0,0 +1,67 @@ +CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +PROJECT_DIR := $(realpath $(CUR_DIR)/../../) + +C_SRCS := $(wildcard *.c) +S_FILES := $(C_SRCS:%.c=%.S) +C_OBJS := $(C_SRCS:%.c=%.o) +BIN_NAME := bin +BIN_ENC_NAME := bin.encrypted +OBJDUMP_FILE := bin.objdump +READELF_FILE := bin.readelf + +C_FLAGS := -Wall -fno-builtin -fno-stack-protector -fverbose-asm -fpic +C_FLAGS += -I../include -L../rusgx_stub -lrusgx_stub +C_FLAGS += -O0 +LINK_FLAGS := -pie -nostdlib -L../rusgx_stub -lrusgx_stub + +.PHONY: all clean test test-without-rusgx + +############################################################################# +# Build +############################################################################# + +all: $(BIN_NAME) $(OBJDUMP_FILE) $(READELF_FILE) + +$(OBJDUMP_FILE): $(BIN_NAME) + objdump -d $(BIN_NAME) > $(OBJDUMP_FILE) + +$(READELF_FILE): $(BIN_NAME) + readelf -a -d $(BIN_NAME) > $(READELF_FILE) + +$(BIN_NAME): $(C_OBJS) + $(CC) $^ $(LINK_FLAGS) -o $(BIN_NAME) + +$(C_OBJS): %.o: %.S + $(CC) $(C_FLAGS) -c $< -o $@ + +$(S_FILES): %.S: %.c + $(CC) $(C_FLAGS) -S $< -o $@ +# ./override_ds_with_fs.sh $@ + +############################################################################# +# Test +############################################################################# + +test: pal librusgx.signed.so $(BIN_ENC_NAME) + RUST_BACKTRACE=1 ./pal ./bin.encrypted + +pal: + cp $(PROJECT_DIR)/src/pal/pal pal + +librusgx.signed.so: + cp $(PROJECT_DIR)/src/libos/librusgx.signed.so librusgx.signed.so + +$(BIN_ENC_NAME): $(BIN_NAME) + $(RM) -f $(BIN_ENC_NAME) + cd $(PROJECT_DIR)/deps/sgx_protect_file/ && \ + ./sgx_protect_file encrypt -i $(CUR_DIR)/$(BIN_NAME) -o $(CUR_DIR)/$(BIN_ENC_NAME) -k 123 + +test-without-rusgx: $(BIN_ENC_NAME) + LD_LIBRARY_PATH=../rusgx_stub/ ./$(BIN_NAME) + +############################################################################# +# Misc +############################################################################# + +clean: + $(RM) -f *.o *.S $(BIN_NAME) $(BIN_ENC_NAME) $(OBJDUMP_FILE) $(READELF_FILE) pal librusgx.signed.so diff --git a/test/src/main.c b/test/src/main.c new file mode 100644 index 00000000..127d511c --- /dev/null +++ b/test/src/main.c @@ -0,0 +1,9 @@ +#include "rusgx_stub.h" + +char str_buf[] = "Hello World!\n"; +unsigned long str_size = sizeof(str_buf); + +void _start(void) { + __rusgx_write(1, str_buf, str_size); + __rusgx_exit(0); +} diff --git a/test/src/override_ds_with_fs.sh b/test/src/override_ds_with_fs.sh new file mode 100755 index 00000000..0e2ad8ff --- /dev/null +++ b/test/src/override_ds_with_fs.sh @@ -0,0 +1,13 @@ +#!/bin/bash +if [ $# -ne 1 ]; then + echo "ERROR: the number of given arguments is incorrect!" + echo + echo "./use_fs " + exit -1 +fi + +S_FILE=$1 +sed -i \ + -e 's/str_size@GOTPCREL/%fs:&/g' \ + -e 's/str_buf@GOTPCREL/%fs:&/g' \ + ${S_FILE}