Load and run a Hello World program

This commit is contained in:
Tate, Hongliang Tian 2018-09-18 13:08:31 +08:00
parent 1428cff243
commit 7671dbf470
37 changed files with 1198 additions and 174 deletions

5
.gitmodules vendored

@ -1,4 +1,7 @@
[submodule "deps/rust-sgx-sdk"] [submodule "deps/rust-sgx-sdk"]
path = deps/rust-sgx-sdk path = deps/rust-sgx-sdk
url = https://github.com/baidu/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

@ -5,7 +5,8 @@ all: build_src build_test
init: init:
git submodule init git submodule init
git submodule update 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: build_src:
@$(MAKE) --no-print-directory -C src @$(MAKE) --no-print-directory -C src

@ -6,7 +6,7 @@ Rusgx is a single-address-space library OS for Intel SGX. It is written in Rust
### Prerequisite ### 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 ### Compile

2
deps/rust-sgx-sdk vendored

@ -1 +1 @@
Subproject commit 32fa6b14326fcf8390891a4c5c86b755fc29d24f Subproject commit f26dcd8f5fce88780c83a7c54b774e6e9d36aa23

@ -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<u64> {
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;

1
deps/sgx_protect_file vendored Submodule

@ -0,0 +1 @@
Subproject commit 3c9a9f063dacf5ef98971e64338d315e107a9083

@ -5,13 +5,15 @@ enclave {
from "sgx_tstd.edl" import *; from "sgx_tstd.edl" import *;
from "sgx_net.edl" import *; from "sgx_net.edl" import *;
from "sgx_time.edl" import *; from "sgx_time.edl" import *;
from "sgx_tprotected_fs.edl" import *;
trusted { trusted {
/* define ECALLs here. */ /* define ECALLs here. */
public int libos_boot(void); public int libos_boot([in, string] const char* executable_path);
public int libos_run(void);
}; };
untrusted { untrusted {
void ocall_print_string([in, string] const char* msg);
}; };
}; };

79
src/libos/Cargo.lock generated

@ -1,16 +1,28 @@
[[package]] [[package]]
name = "Rusgx" name = "Rusgx"
version = "1.0.0" version = "0.0.1"
dependencies = [ dependencies = [
"sgx_tstd 1.0.0", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sgx_types 1.0.0", "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]] [[package]]
name = "sgx_alloc" name = "sgx_alloc"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"sgx_trts 1.0.0", "sgx_trts 1.0.1",
] ]
[[package]] [[package]]
@ -19,39 +31,68 @@ version = "0.1.0"
[[package]] [[package]]
name = "sgx_tprotected_fs" name = "sgx_tprotected_fs"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"sgx_trts 1.0.0", "sgx_trts 1.0.1",
"sgx_types 1.0.0", "sgx_types 1.0.1",
] ]
[[package]] [[package]]
name = "sgx_trts" name = "sgx_trts"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"sgx_types 1.0.0", "sgx_types 1.0.1",
] ]
[[package]] [[package]]
name = "sgx_tstd" name = "sgx_tstd"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"sgx_alloc 1.0.0", "sgx_alloc 1.0.1",
"sgx_build_helper 0.1.0", "sgx_build_helper 0.1.0",
"sgx_tprotected_fs 1.0.0", "sgx_tprotected_fs 1.0.1",
"sgx_trts 1.0.0", "sgx_trts 1.0.1",
"sgx_types 1.0.0", "sgx_types 1.0.1",
"sgx_unwind 0.0.0", "sgx_unwind 0.0.1",
] ]
[[package]] [[package]]
name = "sgx_types" name = "sgx_types"
version = "1.0.0" version = "1.0.1"
[[package]] [[package]]
name = "sgx_unwind" name = "sgx_unwind"
version = "0.0.0" version = "0.0.1"
dependencies = [ 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"

@ -1,14 +1,19 @@
[package] [package]
name = "Rusgx" name = "Rusgx"
version = "1.0.0" version = "0.0.1"
[lib] [lib]
name = "rusgx" name = "libos"
crate-type = ["staticlib"] crate-type = ["staticlib"]
[dependencies]
xmas-elf = "0.6"
lazy_static = { version = "1.1.0", features = ["spin_no_std"] } # Implies nightly
[features] [features]
default = [] default = []
[target.'cfg(not(target_env = "sgx"))'.dependencies] [target.'cfg(not(target_env = "sgx"))'.dependencies]
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" } 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" }

@ -1,14 +1,63 @@
LIB_NAME := librusgx.a include ../sgxenv.mk
SRCS := $(wildcard src/*.rs)
.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 RUSTC_BOOTSTRAP=1 cargo build --release
cp ./target/release/$(LIB_NAME) $(LIB_NAME) cp ./target/release/$(LIBOS_A) $(LIBOS_A)
endif
clean: clean:
@cargo clean @cargo clean
@-$(RM) $(LIB_NAME) @-$(RM) $(LIBOS_ENCLAVE) $(LIBOS_SO) $(LIBOS_A) $(C_OBJS) $(S_OBJS) $(EDL_C_SRCS)

126
src/libos/src/elf_helper.rs Normal file

@ -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<ProgramHeader<'a>, &'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<ProgramHeader<'a>, &'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<usize, &'static str>
{
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<P64>], &'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")
}

@ -1,24 +1,67 @@
#![crate_name = "rusgx"] #![allow(unused)]
#![crate_name = "libos"]
#![crate_type = "staticlib"] #![crate_type = "staticlib"]
#![cfg_attr(not(target_env = "sgx"), no_std)] #![cfg_attr(not(target_env = "sgx"), no_std)]
#![cfg_attr(target_env = "sgx", feature(rustc_private))] #![cfg_attr(target_env = "sgx", feature(rustc_private))]
#![feature(allocator_api)]
#![feature(integer_atomics)]
extern crate sgx_types; extern crate sgx_types;
#[cfg(not(target_env = "sgx"))] #[cfg(not(target_env = "sgx"))]
#[macro_use] #[macro_use]
extern crate sgx_tstd as std; 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" { use std::ffi::CStr; // a borrowed C string
pub fn main() -> c_int; 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] #[no_mangle]
pub extern "C" fn libos_boot() -> sgx_status_t { pub extern "C" fn libos_run() -> i32 {
println!("{}", "LibOS boots"); let _ = backtrace::enable_backtrace("librusgx.signed.so", PrintFormat::Short);
unsafe { main(); } panic::catch_unwind(||{
sgx_status_t::SGX_SUCCESS backtrace::__rust_begin_short_backtrace(||{
let _ = run_task();
})
}).ok();
0
} }
pub mod syscall;

84
src/libos/src/mm.rs Normal file

@ -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<Self, &'static str>
{
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;
}

182
src/libos/src/process.rs Normal file

@ -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<HashMap<u32, Arc<SgxMutex<Process>>>> = {
SgxMutex::new(HashMap::new())
};
}
pub fn spawn_process<P: AsRef<Path>>(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<P: AsRef<Path>>(path: &P) -> io::Result<Vec<u8>> {
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::<u8>::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<Process, &'static str> {
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<usize, &'static str>
{
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<SgxMutex<VecDeque<Task>>> = {
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;
}

19
src/libos/src/syscall.h Normal file

@ -0,0 +1,19 @@
#ifndef __RUSGX_SYSCALL_H__
#define __RUSGX_SYSCALL_H__
#include <sys/types.h>
#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__ */

@ -1,10 +1,11 @@
use sgx_types::*; use sgx_types::*;
use std::collections::HashMap;
// Use the internal syscall wrappers from sgx_tstd // Use the internal syscall wrappers from sgx_tstd
use std::libc_fs as fs; //use std::libc_fs as fs;
use std::libc_io as io; //use std::libc_io as io;
/*
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sys_open(path: * const c_char, flags: c_int, mode: c_int) -> c_int { pub unsafe extern "C" fn sys_open(path: * const c_char, flags: c_int, mode: c_int) -> c_int {
fs::open64(path, flags, mode) 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 { pub unsafe extern "C" fn sys_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssize_t {
io::read(fd, buf, size) io::read(fd, buf, size)
} }
*/
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sys_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t { pub extern fn rusgx_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t {
io::write(fd, buf, size) println!("Hello World!");
size as ssize_t
} }

@ -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;
}

@ -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

44
src/libos/src/task.c Normal file

@ -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);
}

46
src/libos/src/task.h Normal file

@ -0,0 +1,46 @@
#ifndef __RUSGX_TASK_H__
#define __RUSGX_TASK_H__
#ifndef __ASSEMBLY__
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <sys/types.h>
#include <setjmp.h>
// 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 /<path-to-linux-sgx>/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__ */

@ -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

192
src/libos/src/vma.rs Normal file

@ -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<MemObj>,
}
const VMA_MIN_MEM_ALIGN: usize = (4 * 1024);
impl Vma {
pub fn from_program_header<'a>(ph: &ProgramHeader<'a>)
-> Result<Vma, &'static str>
{
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<Self, &'static str>
{
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<usize, &'static str>
{
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;
}

@ -1,4 +1,4 @@
include ../../buildenv.mk include ../sgxenv.mk
EDL_Gen_Files := Enclave_u.c Enclave_u.h EDL_Gen_Files := Enclave_u.c Enclave_u.h
@ -8,7 +8,7 @@ Bin := pal
C_Flags := $(SGX_CFLAGS_U) C_Flags := $(SGX_CFLAGS_U)
Link_Flags := $(SGX_LFLAGS_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) all: $(Bin)

@ -187,6 +187,11 @@ int initialize_enclave(const char* enclave_path)
return 0; return 0;
} }
// Debug
void ocall_print_string(const char* msg) {
printf("%s", msg);
}
/* Application entry */ /* Application entry */
int SGX_CDECL main(int argc, char *argv[]) int SGX_CDECL main(int argc, char *argv[])
{ {
@ -197,11 +202,12 @@ int SGX_CDECL main(int argc, char *argv[])
if (argc != 2) { if (argc != 2) {
printf("ERROR: The expected number of arguments is 1, but given %d\n\n", argc - 1); printf("ERROR: The expected number of arguments is 1, but given %d\n\n", argc - 1);
printf("Usage: pal <path_to_enclave>\n"); printf("Usage: pal <path_to_executable>\n");
return -1; return -1;
} }
const char* enclave_path = argv[1]; const char* executable_path = argv[1];
const char* enclave_path = "librusgx.signed.so";
/* Initialize the enclave */ /* Initialize the enclave */
if(initialize_enclave(enclave_path) < 0){ if(initialize_enclave(enclave_path) < 0){
printf("Enter a character before exit ...\n"); printf("Enter a character before exit ...\n");
@ -209,8 +215,13 @@ int SGX_CDECL main(int argc, char *argv[])
return -1; 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) { if(sgx_ret != SGX_SUCCESS) {
print_error_message(sgx_ret); print_error_message(sgx_ret);
return -1; return -1;

@ -69,11 +69,31 @@ endif
# #
SGX_CFLAGS_T := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector 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 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), # Before use this linker flag, the user should define $(_Other_Enclave_Libs),
# which lists all libraries that are to be part of the enclave. # and $(_Other_Link_Flags)
SGX_LFLAGS_T = $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) $(Other_Link_Flags) \ #
# Linker arguments:
# --no-undefined: Report unresolved symbols.
# --whole-archive <libs> --no-whole-archive: Force including all object files
# in the libraries <libs>. Normally, only required object files are included
# by the linker.
# --start-group <libs> --end-group: Link libraries <libs>, 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=<symbol>=<value>: 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,--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,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \
-Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \
-Wl,--defsym,__ImageBase=0 \ -Wl,--defsym,__ImageBase=0 \

@ -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 build_src: build_rusgx_stub
Enclave_Key := Enclave_private.pem @$(MAKE) -C src
Test_Srcs := $(sort $(filter-out Enclave_t.c, $(wildcard *.c))) build_rusgx_stub:
Test_Targets := $(Test_Srcs:%.c=test-%) @$(MAKE) -C rusgx_stub
Test_Objs := $(Test_Srcs:.c=.o) Enclave_t.o
Test_Enclaves := $(Test_Srcs:.c=.so)
Test_Signed_Enclaves := $(Test_Srcs:.c=.signed.so)
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: clean:
@-$(RM) $(Test_Signed_Enclaves) $(Test_Enclaves) $(Test_Objs) $(EDL_Gen_Files) @$(MAKE) -C rusgx_stub clean
@$(MAKE) -C src clean

@ -1,3 +0,0 @@
int main() {
return 0;
}

@ -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;
}

36
test/include/rusgx_stub.h Normal file

@ -0,0 +1,36 @@
#ifndef __RUSGX_STUB__
#define __RUSGX_STUB__
#include <stddef.h>
#include <sys/types.h>
/*
* 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__ */

23
test/rusgx_stub/Makefile Normal file

@ -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)

@ -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;
}

67
test/src/Makefile Normal file

@ -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

9
test/src/main.c Normal file

@ -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);
}

13
test/src/override_ds_with_fs.sh Executable file

@ -0,0 +1,13 @@
#!/bin/bash
if [ $# -ne 1 ]; then
echo "ERROR: the number of given arguments is incorrect!"
echo
echo "./use_fs <assembly_file>"
exit -1
fi
S_FILE=$1
sed -i \
-e 's/str_size@GOTPCREL/%fs:&/g' \
-e 's/str_buf@GOTPCREL/%fs:&/g' \
${S_FILE}