From 3463196120cc7aafe1b131ecce93ea52cadaa6a5 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 15 Feb 2019 22:08:58 +0800 Subject: [PATCH] impl SGX app: sefs-fuse --- Cargo.toml | 7 -- hello-rust/app/Cargo.toml | 6 ++ hello-rust/app/build.rs | 2 + hello-rust/app/src/enclave.rs | 78 ++++++++++++++++ hello-rust/app/src/main.rs | 132 ++++++--------------------- hello-rust/app/src/sgx_dev.rs | 162 +++++++++++++++++++++++++++++++++ hello-rust/enclave/Cargo.toml | 7 +- hello-rust/enclave/Enclave.edl | 8 +- hello-rust/enclave/src/lib.rs | 137 +++++++++++++++++++++++++--- rcore-fs-sefs/src/lib.rs | 1 + 10 files changed, 414 insertions(+), 126 deletions(-) delete mode 100644 Cargo.toml create mode 100644 hello-rust/app/src/enclave.rs create mode 100644 hello-rust/app/src/sgx_dev.rs diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index f71ba8b..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[workspace] -members = [ - "rcore-fs", - "rcore-fs-sfs", - "rcore-fs-sefs", - "rcore-fs-fuse" -] \ No newline at end of file diff --git a/hello-rust/app/Cargo.toml b/hello-rust/app/Cargo.toml index c81d33d..e9a0c93 100644 --- a/hello-rust/app/Cargo.toml +++ b/hello-rust/app/Cargo.toml @@ -3,8 +3,14 @@ name = "app" version = "1.0.0" authors = ["Baidu"] build = "build.rs" +edition = "2018" [dependencies] sgx_types = "1.0.6" sgx_urts = "1.0.6" dirs = "1.0.2" +fuse = "0.3" +structopt = "0.2" +env_logger = "0.3" +rcore-fs-fuse = { path = "../../rcore-fs-fuse" } +rcore-fs-sefs = { path = "../../rcore-fs-sefs" } diff --git a/hello-rust/app/build.rs b/hello-rust/app/build.rs index 36c9e08..3b3b6ab 100644 --- a/hello-rust/app/build.rs +++ b/hello-rust/app/build.rs @@ -29,6 +29,8 @@ use std::env; fn main () { + println!("cargo:rerun-if-env-changed=SGX_SDK"); + println!("cargo:rerun-if-env-changed=SGX_MODE"); let sdk_dir = env::var("SGX_SDK") .unwrap_or_else(|_| "/opt/intel/sgxsdk".to_string()); diff --git a/hello-rust/app/src/enclave.rs b/hello-rust/app/src/enclave.rs new file mode 100644 index 0000000..252e676 --- /dev/null +++ b/hello-rust/app/src/enclave.rs @@ -0,0 +1,78 @@ +use std::fs; +use std::io::{Read, Write}; +use std::path; + +use sgx_types::*; +use sgx_urts::SgxEnclave; + +static ENCLAVE_FILE: &'static str = "enclave.signed.so"; +static ENCLAVE_TOKEN: &'static str = "enclave.token"; + + +pub fn init_enclave() -> SgxResult { + let mut launch_token: sgx_launch_token_t = [0; 1024]; + let mut launch_token_updated: i32 = 0; + // Step 1: try to retrieve the launch token saved by last transaction + // if there is no token, then create a new one. + // + // try to get the token saved in $HOME */ + let mut home_dir = path::PathBuf::new(); + let use_token = match dirs::home_dir() { + Some(path) => { + println!("[+] Home dir is {}", path.display()); + home_dir = path; + true + } + None => { + println!("[-] Cannot get home dir"); + false + } + }; + + let token_file: path::PathBuf = home_dir.join(ENCLAVE_TOKEN); + ; + if use_token == true { + match fs::File::open(&token_file) { + Err(_) => { + println!("[-] Open token file {} error! Will create one.", token_file.as_path().to_str().unwrap()); + } + Ok(mut f) => { + println!("[+] Open token file success! "); + match f.read(&mut launch_token) { + Ok(1024) => { + println!("[+] Token file valid!"); + } + _ => println!("[+] Token file invalid, will create new token file"), + } + } + } + } + + // Step 2: call sgx_create_enclave to initialize an enclave instance + // Debug Support: set 2nd parameter to 1 + let debug = 1; + let mut misc_attr = sgx_misc_attribute_t { secs_attr: sgx_attributes_t { flags: 0, xfrm: 0 }, misc_select: 0 }; + let enclave = SgxEnclave::create(ENCLAVE_FILE, + debug, + &mut launch_token, + &mut launch_token_updated, + &mut misc_attr)?; + + // Step 3: save the launch token if it is updated + if use_token == true && launch_token_updated != 0 { + // reopen the file with write capablity + match fs::File::create(&token_file) { + Ok(mut f) => { + match f.write_all(&launch_token) { + Ok(()) => println!("[+] Saved updated launch token!"), + Err(_) => println!("[-] Failed to save updated launch token!"), + } + } + Err(_) => { + println!("[-] Failed to save updated enclave token, but doesn't matter"); + } + } + } + + Ok(enclave) +} \ No newline at end of file diff --git a/hello-rust/app/src/main.rs b/hello-rust/app/src/main.rs index ec521ef..741f07c 100644 --- a/hello-rust/app/src/main.rs +++ b/hello-rust/app/src/main.rs @@ -26,96 +26,32 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -extern crate sgx_types; -extern crate sgx_urts; -extern crate dirs; +use std::path::PathBuf; -use sgx_types::*; -use sgx_urts::SgxEnclave; +use structopt::StructOpt; -use std::io::{Read, Write}; -use std::fs; -use std::path; +use rcore_fs_fuse::VfsFuse; +use rcore_fs_sefs as sefs; -static ENCLAVE_FILE: &'static str = "enclave.signed.so"; -static ENCLAVE_TOKEN: &'static str = "enclave.token"; +mod sgx_dev; +mod enclave; -extern { - fn say_something(eid: sgx_enclave_id_t, retval: *mut sgx_status_t, - some_string: *const u8, len: usize) -> sgx_status_t; -} - -fn init_enclave() -> SgxResult { - - let mut launch_token: sgx_launch_token_t = [0; 1024]; - let mut launch_token_updated: i32 = 0; - // Step 1: try to retrieve the launch token saved by last transaction - // if there is no token, then create a new one. - // - // try to get the token saved in $HOME */ - let mut home_dir = path::PathBuf::new(); - let use_token = match dirs::home_dir() { - Some(path) => { - println!("[+] Home dir is {}", path.display()); - home_dir = path; - true - }, - None => { - println!("[-] Cannot get home dir"); - false - } - }; - - let token_file: path::PathBuf = home_dir.join(ENCLAVE_TOKEN);; - if use_token == true { - match fs::File::open(&token_file) { - Err(_) => { - println!("[-] Open token file {} error! Will create one.", token_file.as_path().to_str().unwrap()); - }, - Ok(mut f) => { - println!("[+] Open token file success! "); - match f.read(&mut launch_token) { - Ok(1024) => { - println!("[+] Token file valid!"); - }, - _ => println!("[+] Token file invalid, will create new token file"), - } - } - } - } - - // Step 2: call sgx_create_enclave to initialize an enclave instance - // Debug Support: set 2nd parameter to 1 - let debug = 1; - let mut misc_attr = sgx_misc_attribute_t {secs_attr: sgx_attributes_t { flags:0, xfrm:0}, misc_select:0}; - let enclave = try!(SgxEnclave::create(ENCLAVE_FILE, - debug, - &mut launch_token, - &mut launch_token_updated, - &mut misc_attr)); - - // Step 3: save the launch token if it is updated - if use_token == true && launch_token_updated != 0 { - // reopen the file with write capablity - match fs::File::create(&token_file) { - Ok(mut f) => { - match f.write_all(&launch_token) { - Ok(()) => println!("[+] Saved updated launch token!"), - Err(_) => println!("[-] Failed to save updated launch token!"), - } - }, - Err(_) => { - println!("[-] Failed to save updated enclave token, but doesn't matter"); - }, - } - } - - Ok(enclave) +#[derive(Debug, StructOpt)] +struct Opt { + /// Image file + #[structopt(parse(from_os_str))] + image: PathBuf, + /// Mount point + #[structopt(parse(from_os_str))] + mount_point: PathBuf, } fn main() { + env_logger::init().unwrap(); + + let opt = Opt::from_args(); - let enclave = match init_enclave() { + let enclave = match enclave::init_enclave() { Ok(r) => { println!("[+] Init Enclave Successful {}!", r.geteid()); r @@ -126,26 +62,16 @@ fn main() { }, }; - let input_string = String::from("This is a normal world string passed into Enclave!\n"); - - let mut retval = sgx_status_t::SGX_SUCCESS; - - let result = unsafe { - say_something(enclave.geteid(), - &mut retval, - input_string.as_ptr() as * const u8, - input_string.len()) + let sfs = if opt.image.is_dir() { + let img = sgx_dev::SgxStorage::new(enclave.geteid(), &opt.image); + sefs::SEFS::open(Box::new(img)) + .expect("failed to open sefs") + } else { + std::fs::create_dir_all(&opt.image).unwrap(); + let img = sgx_dev::SgxStorage::new(enclave.geteid(), &opt.image); + sefs::SEFS::create(Box::new(img)) + .expect("failed to create sefs") }; - - match result { - sgx_status_t::SGX_SUCCESS => {}, - _ => { - println!("[-] ECALL Enclave Failed {}!", result.as_str()); - return; - } - } - - println!("[+] say_something success..."); - - enclave.destroy(); + fuse::mount(VfsFuse::new(sfs), &opt.mount_point, &[]) + .expect("failed to mount fs"); } diff --git a/hello-rust/app/src/sgx_dev.rs b/hello-rust/app/src/sgx_dev.rs new file mode 100644 index 0000000..dca3f8e --- /dev/null +++ b/hello-rust/app/src/sgx_dev.rs @@ -0,0 +1,162 @@ +use sgx_types::*; +use rcore_fs_sefs::dev::{File, Storage, DevResult, DeviceError}; +use std::path::*; +use std::fs::remove_file; + +pub struct SgxStorage { + path: PathBuf, +} + +impl SgxStorage { + pub fn new(eid: sgx_enclave_id_t, path: impl AsRef) -> Self { + unsafe { EID = eid; } + + let path_str = path.as_ref().to_str().unwrap(); + let ret = set_sefs_dir(path_str); + assert_eq!(ret, 0); + + SgxStorage { path: path.as_ref().to_path_buf() } + } +} + +impl Storage for SgxStorage { + fn open(&self, file_id: usize) -> DevResult> { + match file_open(file_id) { + 0 => Ok(Box::new(SgxFile { fd: file_id })), + _ => panic!(), + } + } + + fn create(&self, file_id: usize) -> DevResult> { + match file_open(file_id) { + 0 => Ok(Box::new(SgxFile { fd: file_id })), + _ => panic!(), + } + } + + fn remove(&self, file_id: usize) -> DevResult<()> { + let mut path = self.path.to_path_buf(); + path.push(format!("{}", file_id)); + match remove_file(path) { + Ok(_) => Ok(()), + Err(_) => panic!(), + } + } +} + +pub struct SgxFile { + fd: usize, +} + +impl File for SgxFile { + fn read_at(&self, buf: &mut [u8], offset: usize) -> DevResult { + match file_read_at(self.fd, offset, buf) { + size if size > 0 => Ok(size as usize), + e => panic!("read_at {}", e), + } + } + + fn write_at(&self, buf: &[u8], offset: usize) -> DevResult { + match file_write_at(self.fd, offset, buf) { + size if size > 0 => Ok(size as usize), + _ => panic!(), + } + } + + fn set_len(&self, len: usize) -> DevResult<()> { + match file_set_len(self.fd, len) { + 0 => Ok(()), + _ => panic!(), + } + } + + fn flush(&self) -> DevResult<()> { + match file_flush(self.fd) { + 0 => Ok(()), + _ => panic!(), + } + } +} + +impl Drop for SgxFile { + fn drop(&mut self) { + let _ = file_close(self.fd); + } +} + +/// Ecall functions to access SgxFile +extern { + fn ecall_set_sefs_dir(eid: sgx_enclave_id_t, retval: *mut i32, path: *const u8, len: size_t) -> sgx_status_t; + fn ecall_file_open(eid: sgx_enclave_id_t, retval: *mut i32, fd: size_t) -> sgx_status_t; + fn ecall_file_close(eid: sgx_enclave_id_t, retval: *mut i32, fd: size_t) -> sgx_status_t; + fn ecall_file_flush(eid: sgx_enclave_id_t, retval: *mut i32, fd: size_t) -> sgx_status_t; + fn ecall_file_read_at(eid: sgx_enclave_id_t, retval: *mut i32, fd: size_t, offset: size_t, buf: *mut uint8_t, len: size_t) -> sgx_status_t; + fn ecall_file_write_at(eid: sgx_enclave_id_t, retval: *mut i32, fd: size_t, offset: size_t, buf: *const uint8_t, len: size_t) -> sgx_status_t; + fn ecall_file_set_len(eid: sgx_enclave_id_t, retval: *mut i32, fd: size_t, len: size_t) -> sgx_status_t; +} + +/// Must be set when init enclave +static mut EID: sgx_enclave_id_t = 0; + +fn set_sefs_dir(path: &str) -> i32 { + let mut ret_val = -1; + unsafe { + let ret = ecall_set_sefs_dir(EID, &mut ret_val, path.as_ptr(), path.len()); + assert_eq!(ret, sgx_status_t::SGX_SUCCESS); + } + ret_val +} + +fn file_open(fd: usize) -> i32 { + let mut ret_val = -1; + unsafe { + let ret = ecall_file_open(EID, &mut ret_val, fd); + assert_eq!(ret, sgx_status_t::SGX_SUCCESS); + } + ret_val +} + +fn file_close(fd: usize) -> i32 { + let mut ret_val = -1; + unsafe { + let ret = ecall_file_close(EID, &mut ret_val, fd); + assert_eq!(ret, sgx_status_t::SGX_SUCCESS); + } + ret_val +} + +fn file_flush(fd: usize) -> i32 { + let mut ret_val = -1; + unsafe { + let ret = ecall_file_flush(EID, &mut ret_val, fd); + assert_eq!(ret, sgx_status_t::SGX_SUCCESS); + } + ret_val +} + +fn file_read_at(fd: usize, offset: usize, buf: &mut [u8]) -> i32 { + let mut ret_val = -1; + unsafe { + let ret = ecall_file_read_at(EID, &mut ret_val, fd, offset, buf.as_mut_ptr(), buf.len()); + assert_eq!(ret, sgx_status_t::SGX_SUCCESS); + } + ret_val +} + +fn file_write_at(fd: usize, offset: usize, buf: &[u8]) -> i32 { + let mut ret_val = -1; + unsafe { + let ret = ecall_file_write_at(EID, &mut ret_val, fd, offset, buf.as_ptr(), buf.len()); + assert_eq!(ret, sgx_status_t::SGX_SUCCESS); + } + ret_val +} + +fn file_set_len(fd: usize, len: usize) -> i32 { + let mut ret_val = -1; + unsafe { + let ret = ecall_file_set_len(EID, &mut ret_val, fd, len); + assert_eq!(ret, sgx_status_t::SGX_SUCCESS); + } + ret_val +} diff --git a/hello-rust/enclave/Cargo.toml b/hello-rust/enclave/Cargo.toml index a601af1..65577cd 100644 --- a/hello-rust/enclave/Cargo.toml +++ b/hello-rust/enclave/Cargo.toml @@ -10,6 +10,9 @@ crate-type = ["staticlib"] [features] default = [] +[dependencies] +lazy_static = { version = "1.1.0", features = ["spin_no_std"] } # Implies nightly + [target.'cfg(not(target_env = "sgx"))'.dependencies] -sgx_types = { path = "../../../rust-sgx-sdk/sgx_types" } -sgx_tstd = { path = "../../../rust-sgx-sdk/sgx_tstd" } +sgx_types = "1.0.6" +sgx_tstd = "1.0.6" diff --git a/hello-rust/enclave/Enclave.edl b/hello-rust/enclave/Enclave.edl index 5130813..cda5c20 100644 --- a/hello-rust/enclave/Enclave.edl +++ b/hello-rust/enclave/Enclave.edl @@ -39,6 +39,12 @@ enclave { trusted { /* define ECALLs here. */ - public sgx_status_t say_something([in, size=len] const uint8_t* some_string, size_t len); + public int ecall_set_sefs_dir([in, size=len] const char* path, size_t len); + public int ecall_file_open(size_t fd); + public int ecall_file_close(size_t fd); + public int ecall_file_flush(size_t fd); + public int ecall_file_read_at(size_t fd, size_t offset, [out, size=len] uint8_t* buf, size_t len); + public int ecall_file_write_at(size_t fd, size_t offset, [in, size=len] const uint8_t* buf, size_t len); + public int ecall_file_set_len(size_t fd, size_t len); }; }; diff --git a/hello-rust/enclave/src/lib.rs b/hello-rust/enclave/src/lib.rs index b6ef130..5c37211 100644 --- a/hello-rust/enclave/src/lib.rs +++ b/hello-rust/enclave/src/lib.rs @@ -32,26 +32,137 @@ #![cfg_attr(not(target_env = "sgx"), no_std)] #![cfg_attr(target_env = "sgx", feature(rustc_private))] -extern crate sgx_types; +#[macro_use] +extern crate lazy_static; #[cfg(not(target_env = "sgx"))] #[macro_use] extern crate sgx_tstd as std; +extern crate sgx_types; -use sgx_types::*; -use std::string::String; +use std::collections::BTreeMap; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::path::PathBuf; +use std::sgxfs::{OpenOptions, SgxFile}; +use std::sync::{SgxMutex as Mutex, SgxRwLock as RwLock}; +use std::untrusted::path::PathEx; use std::vec::Vec; -use std::io::{self, Write}; -use std::slice; -use std::sgxfs::SgxFile; #[no_mangle] -pub extern "C" fn say_something(some_string: *const u8, some_len: usize) -> sgx_status_t { +pub extern "C" fn ecall_set_sefs_dir(path: *const u8, len: usize) -> i32 { + unsafe { + assert!(PATH.is_none()); + let path = std::slice::from_raw_parts(path, len); + let path = std::str::from_utf8(path).unwrap(); + let path = PathBuf::from(path); + PATH = Some(path); + 0 + } +} + +#[no_mangle] +pub extern "C" fn ecall_file_open(fd: usize) -> i32 { + let path = get_path(fd); + let file = match OpenOptions::new().append(true).update(true).open(&path) { + Ok(f) => f, + Err(e) => { println!("open err {}", e); panic!() } + }; + let file = LockedFile(Mutex::new(file)); + let mut files = FILES.write().unwrap(); + files.insert(fd, file); + 0 +} + +#[no_mangle] +pub extern "C" fn ecall_file_close(fd: usize) -> i32 { + let mut files = FILES.write().unwrap(); + files.remove(&fd); + 0 +} + +#[no_mangle] +pub extern "C" fn ecall_file_flush(fd: usize) -> i32 { + let files = FILES.read().unwrap(); + let mut file = files[&fd].0.lock().unwrap(); + match file.flush() { + Ok(_) => 0, + Err(_) => -1, + } +} + +#[no_mangle] +pub extern "C" fn ecall_file_read_at(fd: usize, offset: usize, buf: *mut u8, len: usize) -> i32 { + let files = FILES.read().unwrap(); + let mut file = files[&fd].0.lock().unwrap(); + + println!("read_at fd = {}, offset = {}, len = {}", fd, offset, len); + let offset = offset as u64; + match file.seek(SeekFrom::Start(offset)) { + Ok(real_offset) if real_offset == offset => {}, + _ => return -1, + } + let buf = unsafe { std::slice::from_raw_parts_mut(buf, len) }; + match file.read(buf) { + Ok(len) => len as i32, + Err(e) => {println!("read_at fail {}", e); -2}, + } +} + +#[no_mangle] +pub extern "C" fn ecall_file_write_at(fd: usize, offset: usize, buf: *const u8, len: usize) -> i32 { + let files = FILES.read().unwrap(); + let mut file = files[&fd].0.lock().unwrap(); + + let offset = offset as u64; + println!("write_at fd = {}, offset = {}, len = {}", fd, offset, len); + match file.seek(SeekFrom::Start(offset)) { + Ok(real_offset) if real_offset == offset => {}, + _ => return -1, + } + let buf = unsafe { std::slice::from_raw_parts(buf, len) }; + match file.write(buf) { + Ok(len) => len as i32, + Err(_) => return -2, + } +} + +#[no_mangle] +pub extern "C" fn ecall_file_set_len(fd: usize, len: usize) -> i32 { + let files = FILES.read().unwrap(); + let mut file = files[&fd].0.lock().unwrap(); + + println!("set_len fd = {}, len = {}", fd, len); + let current_len = match file.seek(SeekFrom::End(0)) { + Ok(len) => len as usize, + Err(_) => return -1, + }; + if current_len < len { + let mut zeros = Vec::::new(); + zeros.resize(len - current_len, 0); + match file.write(zeros.as_slice()) { + Ok(_) => {} + Err(_) => return -2, + } + } + // TODO: how to shrink a file? + 0 +} + +static mut PATH: Option = None; +lazy_static! { + static ref FILES: RwLock> = RwLock::new(BTreeMap::new()); +} - let mut file = SgxFile::create("test").unwrap(); - file.write(b"hello").unwrap(); +struct LockedFile(Mutex); - // Ocall to normal world for output - println!("{}", "hello"); +// `sgx_tstd::sgxfs::SgxFile` not impl Send ... +unsafe impl Send for LockedFile {} +unsafe impl Sync for LockedFile {} - sgx_status_t::SGX_SUCCESS -} \ No newline at end of file +/// Get file path of `fd`. +/// +/// `ecall_set_sefs_dir` must be called first, or this will panic. +fn get_path(fd: usize) -> PathBuf { + let mut path = unsafe { PATH.as_ref().unwrap().clone() }; + path.push(format!("{}", fd)); + path +} diff --git a/rcore-fs-sefs/src/lib.rs b/rcore-fs-sefs/src/lib.rs index a2f5075..e5750c4 100644 --- a/rcore-fs-sefs/src/lib.rs +++ b/rcore-fs-sefs/src/lib.rs @@ -445,6 +445,7 @@ impl SEFS { bitset }; let meta_file = device.create(0)?; + meta_file.set_len(blocks * BLKSIZE)?; let sefs = SEFS { super_block: RwLock::new(Dirty::new_dirty(super_block)),