Add Occlum.json. No more configs hardcoded in code

1. Add Occlum.json as Occlum's config file
2. Add tools/bin/build_enclave
3. Add tools/bin/protect_integrity
4. Validate Occlum.json.protected on LibOS startup
5. Parse Occlum.json.protected on LibOS startup
6. Config enclave size using Occlum.json
7. Config process memory sizes using Occlum.json
This commit is contained in:
Tate, Hongliang Tian 2019-08-09 09:19:51 +00:00
parent cff0de1c39
commit 76f91a1aa3
30 changed files with 1824 additions and 37 deletions

@ -5,7 +5,9 @@ all: src
submodule:
git submodule init
git submodule update
cd deps/rust-sgx-sdk && git apply ../rust-sgx-sdk.patch
cd deps/sefs/sefs-fuse && make
cd tools/protect-integrity && make
src:
@$(MAKE) --no-print-directory -C src

387
deps/rust-sgx-sdk.patch vendored Normal file

@ -0,0 +1,387 @@
From 5a6f0000e5a5d644e547fcf8a7c9c87f89ae5935 Mon Sep 17 00:00:00 2001
From: Liu Shuang <ls123674@antfin.com>
Date: Tue, 6 Aug 2019 06:59:49 +0000
Subject: [PATCH] Add support for integrity-only SGX protected files
1. Add SgxFile::open_integrity_only API
1. Add SgxFile::create_integrity_only API
2. Add the unit test for integrity-only SgxFile
---
samplecode/unit-test/enclave/src/lib.rs | 2 +
samplecode/unit-test/enclave/src/test_file.rs | 41 +++++++++++++
sgx_tprotected_fs/src/fs.rs | 86 +++++++++++++++++++++++++++
sgx_tstd/src/sgxfs.rs | 39 +++++++++++-
sgx_tstd/src/sys/sgxfs.rs | 40 +++++++++++--
sgx_types/src/function.rs | 4 ++
6 files changed, 205 insertions(+), 7 deletions(-)
diff --git a/samplecode/unit-test/enclave/src/lib.rs b/samplecode/unit-test/enclave/src/lib.rs
index e368e26..45579da 100644
--- a/samplecode/unit-test/enclave/src/lib.rs
+++ b/samplecode/unit-test/enclave/src/lib.rs
@@ -148,6 +148,8 @@ fn test_main_entrance() -> sgx_status_t {
test_serialize_enum,
// std::sgxfs
test_sgxfs,
+ // std::sgxfs in integrity-only mode
+ test_sgxfs_integrity_only,
// std::fs
test_fs,
// std::fs untrusted mode
diff --git a/samplecode/unit-test/enclave/src/test_file.rs b/samplecode/unit-test/enclave/src/test_file.rs
index e9a85a7..0dbc805 100644
--- a/samplecode/unit-test/enclave/src/test_file.rs
+++ b/samplecode/unit-test/enclave/src/test_file.rs
@@ -138,3 +138,44 @@ pub fn test_fs_untrusted_fs_feature_enabled() {
assert!(f.is_ok());
}
}
+
+pub fn test_sgxfs_integrity_only() {
+ let write_data = {
+ let read_result = std::fs::read_to_string("../Makefile");
+ assert!(read_result.is_ok());
+ read_result.unwrap()
+ };
+ let path = "sgx_file_integrity_only.data";
+ let mut new_file = {
+ let create_result = SgxFile::create_integrity_only(path);
+ assert!(create_result.is_ok());
+ create_result.unwrap()
+ };
+ let _ = new_file.write_all(&write_data.as_bytes());
+ let write_mac = {
+ let mac_result = new_file.get_mac();
+ assert!(mac_result.is_ok());
+ mac_result.unwrap()
+ };
+ drop(new_file);
+
+ let mut read_data = String::new();
+ let mut open_file = {
+ let open_result = SgxFile::open_integrity_only(path);
+ assert!(open_result.is_ok());
+ open_result.unwrap()
+ };
+ let _ = open_file.read_to_string(&mut read_data);
+ let read_mac = {
+ let mac_result = open_file.get_mac();
+ assert!(mac_result.is_ok());
+ mac_result.unwrap()
+ };
+ drop(open_file);
+
+ assert_eq!(&write_data[..], &read_data[..]);
+ assert_eq!(&write_mac, &read_mac);
+
+ let remove_result = remove_file(path);
+ assert!(remove_result.is_ok());
+}
diff --git a/sgx_tprotected_fs/src/fs.rs b/sgx_tprotected_fs/src/fs.rs
index d1e438c..b9e508f 100644
--- a/sgx_tprotected_fs/src/fs.rs
+++ b/sgx_tprotected_fs/src/fs.rs
@@ -47,6 +47,16 @@ unsafe fn rsgx_fopen(filename: &CStr, mode: &CStr, key: &sgx_key_128bit_t) -> Sy
}
}
+unsafe fn rsgx_fopen_integrity_only(filename: &CStr, mode: &CStr) -> SysResult<SGX_FILE> {
+
+ let file = sgx_fopen_integrity_only(filename.as_ptr(), mode.as_ptr());
+ if file.is_null() {
+ Err(errno())
+ } else {
+ Ok(file)
+ }
+}
+
unsafe fn rsgx_fopen_auto_key(filename: &CStr, mode: &CStr) -> SysResult<SGX_FILE> {
let file = sgx_fopen_auto_key(filename.as_ptr(), mode.as_ptr());
@@ -218,6 +228,16 @@ unsafe fn rsgx_fimport_auto_key(filename: &CStr, key: &sgx_key_128bit_t) -> SysE
}
}
+unsafe fn rsgx_fget_mac(stream: SGX_FILE, mac: &mut sgx_aes_gcm_128bit_tag_t) -> SysError {
+
+ let ret = sgx_fget_mac(stream, mac as * mut sgx_aes_gcm_128bit_tag_t);
+ if ret == 0 {
+ Ok(())
+ } else {
+ Err(errno())
+ }
+}
+
pub struct SgxFileStream {
stream: SGX_FILE
}
@@ -303,6 +323,48 @@ impl SgxFileStream {
}
///
+ /// The open function creates or opens a protected file in the integrity-only mode.
+ ///
+ /// # Description
+ ///
+ /// open_integrity_only is different from open and open_auto_key.
+ /// The protected file opened by this function is in integrity-only mode.
+ /// In this mode, the content of the file is not encrypted, only MACed.
+ ///
+ /// A protected file created by open_integrity_only cannot later be openned
+ /// by open or open_auto_key and vice versa.
+ ///
+ /// # Parameters
+ ///
+ /// **filename**
+ ///
+ /// The name of the file to be created or opened.
+ ///
+ /// **mode**
+ ///
+ /// The file open mode string. Allowed values are any combination of r, w or a, with possible +
+ /// and possible b (since string functions are currently not sup- ported, b is meaningless).
+ ///
+ /// # Requirements
+ ///
+ /// Header: sgx_tprotected_fs.edl
+ ///
+ /// Library: libsgx_tprotected_fs.a
+ ///
+ /// This API is provided by Occlum's fork of Intel SGX SDK.
+ ///
+ /// # Return value
+ ///
+ /// If the function succeeds, it returns a valid file pointer, which can be used by all the other functions
+ /// in the Protected FS API, otherwise, error code is returned.
+ ///
+ pub fn open_integrity_only(filename: &CStr, mode: &CStr) -> SysResult<SgxFileStream> {
+ unsafe {
+ rsgx_fopen_integrity_only(filename, mode).map(|f| SgxFileStream{ stream: f})
+ }
+ }
+
+ ///
/// The read function reads the requested amount of data from the file, and extends the file pointer by that amount.
///
/// # Description
@@ -542,6 +604,30 @@ impl SgxFileStream {
pub fn clear_cache(&self) -> SysError {
unsafe { rsgx_fclear_cache(self.stream) }
}
+
+ ///
+ /// The get_mac function returns the MAC of the protected file.
+ ///
+ /// # Description
+ ///
+ /// # Requirements
+ ///
+ /// Header: sgx_tprotected_fs.edl
+ ///
+ /// Library: libsgx_tprotected_fs.a
+ ///
+ /// This API is provided by Occlum's fork of Intel SGX SDK.
+ ///
+ /// # Return value
+ ///
+ /// If the function succeeded, the MAC is returned.
+ /// If the function failed, error code is returned.
+ ///
+ pub fn get_mac(&self) -> SysResult<sgx_aes_gcm_128bit_tag_t> {
+ let mut mac : sgx_aes_gcm_128bit_tag_t = Default::default();
+ unsafe { rsgx_fget_mac(self.stream, &mut mac)?; }
+ Ok(mac)
+ }
}
///
diff --git a/sgx_tstd/src/sgxfs.rs b/sgx_tstd/src/sgxfs.rs
index b03d174..1b2ce52 100644
--- a/sgx_tstd/src/sgxfs.rs
+++ b/sgx_tstd/src/sgxfs.rs
@@ -28,7 +28,7 @@
//! Filesystem manipulation operations.
-use sgx_types::sgx_key_128bit_t;
+use sgx_types::{sgx_key_128bit_t, sgx_aes_gcm_128bit_tag_t};
use io::{self, SeekFrom, Seek, Read, Initializer, Write};
use path::Path;
use sys::sgxfs as fs_imp;
@@ -120,6 +120,19 @@ impl SgxFile {
OpenOptions::new().read(true).open(path.as_ref())
}
+ /// Attempts to open a file in read-only and integrity-only mode.
+ ///
+ /// See the [`OpenOptions::open`] method for more details.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if `path` does not already exist.
+ /// Other errors may also be returned according to [`OpenOptions::open`].
+ ///
+ pub fn open_integrity_only<P: AsRef<Path>>(path: P) -> io::Result<SgxFile> {
+ OpenOptions::new().read(true).open_integrity_only(path.as_ref())
+ }
+
/// Opens a file in write-only mode.
///
/// This function will create a file if it does not exist,
@@ -129,6 +142,15 @@ impl SgxFile {
OpenOptions::new().write(true).open(path.as_ref())
}
+ /// Opens a file in write-only and integrity-only mode.
+ ///
+ /// This function will create a file if it does not exist,
+ /// and will truncate it if it does.
+ ///
+ pub fn create_integrity_only<P: AsRef<Path>>(path: P) -> io::Result<SgxFile> {
+ OpenOptions::new().write(true).open_integrity_only(path.as_ref())
+ }
+
pub fn open_ex<P: AsRef<Path>>(path: P, key: &sgx_key_128bit_t) -> io::Result<SgxFile> {
OpenOptions::new().read(true).open_ex(path.as_ref(), key)
}
@@ -148,6 +170,12 @@ impl SgxFile {
pub fn clear_cache(&self) -> io::Result<()> {
self.inner.clear_cache()
}
+
+ /// Gets the MAC of the SGX protected file
+ ///
+ pub fn get_mac(&self) -> io::Result<sgx_aes_gcm_128bit_tag_t> {
+ self.inner.get_mac()
+ }
}
impl AsInner<fs_imp::SgxFile> for SgxFile {
@@ -284,6 +312,10 @@ impl OpenOptions {
self._open_ex(path.as_ref(), key)
}
+ pub fn open_integrity_only<P: AsRef<Path>>(&self, path: P) -> io::Result<SgxFile> {
+ self._open_integrity_only(path.as_ref())
+ }
+
fn _open(&self, path: &Path) -> io::Result<SgxFile> {
let inner = fs_imp::SgxFile::open(path, &self.0)?;
Ok(SgxFile { inner: inner })
@@ -293,6 +325,11 @@ impl OpenOptions {
let inner = fs_imp::SgxFile::open_ex(path, &self.0, key)?;
Ok(SgxFile { inner: inner })
}
+
+ fn _open_integrity_only(&self, path: &Path) -> io::Result<SgxFile> {
+ let inner = fs_imp::SgxFile::open_integrity_only(path, &self.0)?;
+ Ok(SgxFile { inner: inner })
+ }
}
impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
diff --git a/sgx_tstd/src/sys/sgxfs.rs b/sgx_tstd/src/sys/sgxfs.rs
index a32814d..ebc3627 100644
--- a/sgx_tstd/src/sys/sgxfs.rs
+++ b/sgx_tstd/src/sys/sgxfs.rs
@@ -26,7 +26,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-use sgx_types::{sgx_status_t, sgx_key_128bit_t};
+use sgx_types::{sgx_status_t, sgx_key_128bit_t, sgx_aes_gcm_128bit_tag_t};
use sgx_trts::libc;
use sgx_tprotected_fs::{self, SgxFileStream};
use os::unix::prelude::*;
@@ -87,7 +87,7 @@ impl SgxFile {
let path = cstr(path)?;
let mode = opts.get_access_mode()?;
let opts = CString::new(mode.as_bytes())?;
- SgxFile::open_c(&path, &opts, &sgx_key_128bit_t::default(), true)
+ SgxFile::open_c(&path, &opts, &sgx_key_128bit_t::default(), true, false)
}
pub fn open_ex(path: &Path, opts: &OpenOptions, key: &sgx_key_128bit_t) -> io::Result<SgxFile> {
@@ -95,12 +95,23 @@ impl SgxFile {
let path = cstr(path)?;
let mode = opts.get_access_mode()?;
let opts = CString::new(mode.as_bytes())?;
- SgxFile::open_c(&path, &opts, key, false)
+ SgxFile::open_c(&path, &opts, key, false, false)
}
- pub fn open_c(path: &CStr, opts: &CStr, key: &sgx_key_128bit_t, auto: bool) -> io::Result<SgxFile> {
+ pub fn open_integrity_only(path: &Path, opts: &OpenOptions) -> io::Result<SgxFile> {
- let file = if auto == true {
+ let path = cstr(path)?;
+ let mode = opts.get_access_mode()?;
+ let opts = CString::new(mode.as_bytes())?;
+ SgxFile::open_c(&path, &opts, &sgx_key_128bit_t::default(), false, true)
+
+ }
+
+ pub fn open_c(path: &CStr, opts: &CStr, key: &sgx_key_128bit_t, auto: bool, integrity_only: bool) -> io::Result<SgxFile> {
+
+ let file = if integrity_only == true {
+ SgxFileStream::open_integrity_only(path, opts)
+ } else if auto == true {
SgxFileStream::open_auto_key(path, opts)
} else {
SgxFileStream::open(path, opts, key)
@@ -233,6 +244,23 @@ impl SgxFile {
}
})
}
+
+ pub fn get_mac(&self) -> io::Result<sgx_aes_gcm_128bit_tag_t> {
+
+ self.0.get_mac().map_err(|err| {
+ match err {
+ 1 => Error::from_sgx_error(sgx_status_t::SGX_ERROR_UNEXPECTED),
+ 2 => Error::from_sgx_error(sgx_status_t::SGX_ERROR_INVALID_PARAMETER),
+ 3 => Error::from_sgx_error(sgx_status_t::SGX_ERROR_OUT_OF_MEMORY),
+ 4 | 5 => Error::from_raw_os_error(err),
+ r if r > 4096 => {
+ let status = sgx_status_t::from_repr(r as u32).unwrap_or(sgx_status_t::SGX_ERROR_UNEXPECTED);
+ Error::from_sgx_error(status)
+ },
+ _ => Error::from_raw_os_error(err),
+ }
+ })
+ }
}
pub fn remove(path: &Path) -> io::Result<()> {
@@ -324,4 +352,4 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let ret = io::copy(&mut reader, &mut writer)?;
fs::set_permissions(to, perm)?;
Ok(ret)
-}
\ No newline at end of file
+}
diff --git a/sgx_types/src/function.rs b/sgx_types/src/function.rs
index 91869f7..fdd8a04 100644
--- a/sgx_types/src/function.rs
+++ b/sgx_types/src/function.rs
@@ -551,6 +551,8 @@ extern {
pub fn sgx_fopen_auto_key(filename: * const ::c_char, mode: * const ::c_char) -> SGX_FILE;
+ pub fn sgx_fopen_integrity_only(filename: * const ::c_char, mode: * const ::c_char) -> SGX_FILE;
+
pub fn sgx_fwrite(ptr: * const ::c_void,
size: ::size_t,
count: ::size_t,
@@ -582,6 +584,8 @@ extern {
pub fn sgx_fimport_auto_key(filename: * const ::c_char, key: * const sgx_key_128bit_t) -> ::int32_t;
pub fn sgx_fclear_cache(stream: SGX_FILE) -> ::int32_t;
+
+ pub fn sgx_fget_mac(stream: SGX_FILE, mac: * mut sgx_aes_gcm_128bit_tag_t) -> ::int32_t;
}
/* intel sgx sdk 2.0 */
--
2.7.4

42
src/libos/Cargo.lock generated

@ -12,6 +12,8 @@ dependencies = [
"rcore-fs-mountfs 0.1.0",
"rcore-fs-ramfs 0.1.0",
"rcore-fs-sefs 0.1.0",
"serde 1.0.84",
"serde_json 1.0.36",
"sgx_trts 1.0.6",
"sgx_tstd 1.0.6",
"sgx_types 1.0.6",
@ -98,6 +100,13 @@ name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itoa"
version = "0.4.1"
dependencies = [
"sgx_tstd 1.0.6",
]
[[package]]
name = "lazy_static"
version = "1.3.0"
@ -167,6 +176,38 @@ dependencies = [
"static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.84"
dependencies = [
"serde_derive 1.0.84",
"sgx_tstd 1.0.6",
]
[[package]]
name = "serde_derive"
version = "1.0.84"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.36"
dependencies = [
"itoa 0.4.1",
"ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.84",
"sgx_tstd 1.0.6",
]
[[package]]
name = "sgx_alloc"
version = "1.0.6"
@ -287,6 +328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
"checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1"

@ -15,6 +15,8 @@ rcore-fs = { path = "../../deps/sefs/rcore-fs" }
rcore-fs-sefs = { path = "../../deps/sefs/rcore-fs-sefs" }
rcore-fs-ramfs = { path = "../../deps/sefs/rcore-fs-ramfs" }
rcore-fs-mountfs = { path = "../../deps/sefs/rcore-fs-mountfs" }
serde = { path = "../../deps/rust-sgx-sdk/third_party/serde-rs/serde/serde", features = ["derive"] }
serde_json = { path = "../../deps/rust-sgx-sdk/third_party/serde-rs/json" }
[features]
default = ["integrity_only_opt", "sgx_file_cache"]

@ -1,8 +1,7 @@
include ../sgxenv.mk
DEBUG=1
DEBUG := 1
LIBOS_ENCLAVE := libocclum.signed.so
LIBOS_SO := libocclum.so # Link $(LIBOS_A), $(C_OBJS) and all dependencies
LIBOS_A := libocclum_rs.a # Built from Rust code
@ -17,17 +16,25 @@ ENCLAVE_CONFIG := Enclave_config.xml
ENCLAVE_KEY := Enclave_private.pem
C_FLAGS := $(SGX_CFLAGS_T) -fno-stack-protector -I./include/
# Pass builtin values by defining macros
#
# The MAC of Occlum config file must be builtin into the binary
ifdef OCCLUM_BUILTIN_CONF_FILE_MAC
C_FLAGS += -DOCCLUM_BUILTIN_CONF_FILE_MAC='"$(OCCLUM_BUILTIN_CONF_FILE_MAC)"'
endif
# The total size of user-space memory must be builtin into the binary
ifdef OCCLUM_BUILTIN_VM_USER_SPACE_SIZE
C_FLAGS += -DOCCLUM_BUILTIN_VM_USER_SPACE_SIZE='($(OCCLUM_BUILTIN_VM_USER_SPACE_SIZE))'
endif
_Other_Link_Flags := -L$(RUST_SGX_SDK_DIR)/compiler-rt/ -L.
_Other_Enclave_Libs := -lcompiler-rt-patch -locclum_rs -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 => $@"
all: $(LIBOS_SO)
$(LIBOS_SO): compiler-rt $(LIBOS_A) $(C_OBJS) $(S_OBJS)
@$(CC) $(C_OBJS) $(S_OBJS) -o $@ $(LINK_FLAGS)
@ -60,6 +67,9 @@ $(LIBOS_A): $(RUST_SRCS)
@echo "CARGO (release) => $(LIBOS_A)"
endif
clean-builtin:
@-$(RM) src/builtin/*.o
clean:
@cargo clean
@-$(RM) $(LIBOS_ENCLAVE) $(LIBOS_SO) $(LIBOS_A) $(C_OBJS) $(S_OBJS) $(EDL_C_SRCS)
@-$(RM) $(LIBOS_SO) $(LIBOS_A) $(C_OBJS) $(S_OBJS) $(EDL_C_SRCS)

@ -0,0 +1,14 @@
#include <stddef.h>
// The 128-bit MAC of Occlum.json
// Should be provided by Makefile; Set it to all zeros by default.
#ifndef OCCLUM_BUILTIN_CONF_FILE_MAC
#define ALL_ZEROS_32BIT "00-00-00-00"
#define ALL_ZEROS_128BIT (ALL_ZEROS_32BIT"-"ALL_ZEROS_32BIT"-"\
ALL_ZEROS_32BIT"-"ALL_ZEROS_32BIT)
#define OCCLUM_BUILTIN_CONF_FILE_MAC ALL_ZEROS_128BIT
#endif
const char* conf_get_hardcoded_file_mac(void) {
return OCCLUM_BUILTIN_CONF_FILE_MAC;
}

@ -0,0 +1,17 @@
#include <stddef.h>
// The total size of the memory available to user programs
// Should be provided by Makefile
#ifndef OCCLUM_BUILTIN_VM_USER_SPACE_SIZE
#define OCCLUM_BUILTIN_VM_USER_SPACE_SIZE (128*1024*1024)
#endif
static char __preallocated_memory[OCCLUM_BUILTIN_VM_USER_SPACE_SIZE]
__attribute__ ((
section(".exectuable_data,\"awx\",@nobits#"),
aligned(4096))) = {0};
void vm_get_preallocated_user_space_memory(void** paddr, size_t* psize) {
*paddr = __preallocated_memory;
*psize = sizeof(__preallocated_memory);
}

307
src/libos/src/config.rs Normal file

@ -0,0 +1,307 @@
use super::*;
use serde::{Deserialize, Serialize};
use std::sgxfs::{SgxFile};
const LIBOS_CONFIG_PATH : &str = "Occlum.json.protected";
lazy_static! {
pub static ref LIBOS_CONFIG: Config = {
let mut config_file = {
let config_file = match SgxFile::open_integrity_only(LIBOS_CONFIG_PATH) {
Err(_) => panic!("Failed to find or open Occlum's config file: {}",
LIBOS_CONFIG_PATH),
Ok(file) => file,
};
let actual_mac = match config_file.get_mac() {
Err(_) => panic!("Failed to get the MAC of Occlum's config file: {}",
LIBOS_CONFIG_PATH),
Ok(mac) => mac,
};
let expected_mac = conf_get_hardcoded_file_mac();
if actual_mac != expected_mac {
panic!("The MAC of Occlum's config file is not as expected: {}",
LIBOS_CONFIG_PATH);
}
config_file
};
let config_json = {
let mut config_json = String::new();
config_file.read_to_string(&mut config_json)
.map_err(|_| {
panic!("Failed to read from Occlum's config file: {}",
LIBOS_CONFIG_PATH);
});
config_json
};
let config_input: InputConfig = match serde_json::from_str(&config_json) {
Err(_) => panic!("Failed to parse JSON from Occlum's config file: {}",
LIBOS_CONFIG_PATH),
Ok(config_input) => config_input
};
let config = match Config::from_input(&config_input) {
Err(_) => panic!("Found invalid config in Occlum's config file: {}",
LIBOS_CONFIG_PATH),
Ok(config) => config
};
config
};
}
fn conf_get_hardcoded_file_mac() -> sgx_aes_gcm_128bit_tag_t {
// Wrap the unsafe C version to get the safe Rust version
extern "C" {
fn conf_get_hardcoded_file_mac() -> *const c_char;
}
let mac_str = unsafe {
CStr::from_ptr(conf_get_hardcoded_file_mac())
.to_str()
.expect("Invalid MAC")
};
let mac = parse_mac(mac_str)
.expect("Invalid MAC");
mac
}
fn parse_mac(mac_str: &str) -> Result<sgx_aes_gcm_128bit_tag_t, Error> {
let bytes_str_vec = {
let bytes_str_vec : Vec<&str> = mac_str.split("-").collect();
if bytes_str_vec.len() != 16 {
return errno!(EINVAL, "The length or format of MAC string is invalid");
}
bytes_str_vec
};
let mut mac : sgx_aes_gcm_128bit_tag_t = Default::default();
for (byte_i, byte_str) in bytes_str_vec.iter().enumerate() {
mac[byte_i] = u8::from_str_radix(byte_str, 16)
.map_err(|_| Error::new(Errno::EINVAL, "The format of MAC string is invalid"))?;
}
Ok(mac)
}
#[derive(Debug)]
pub struct Config {
pub vm: ConfigVM,
pub process: ConfigProcess,
pub mount: Vec<ConfigMount>,
}
#[derive(Debug)]
pub struct ConfigVM {
pub user_space_size : usize,
}
#[derive(Debug)]
pub struct ConfigProcess {
pub default_stack_size: usize,
pub default_heap_size: usize,
pub default_mmap_size: usize,
}
#[derive(Debug)]
pub struct ConfigMount {
pub type_: String,
pub target: String,
pub source: Option<String>,
pub options: ConfigMountOptions,
}
#[derive(Debug)]
pub struct ConfigMountOptions {
pub integrity_only: bool,
pub mac: Option<String>,
}
impl Config {
fn from_input(input: &InputConfig) -> Result<Config, Error> {
let vm = ConfigVM::from_input(&input.vm)?;
let process = ConfigProcess::from_input(&input.process)?;
let mount = {
let mut mount = Vec::new();
for input_mount in &input.mount {
mount.push(ConfigMount::from_input(&input_mount)?);
}
mount
};
Ok(Config { vm, process, mount })
}
}
impl ConfigVM {
fn from_input(input: &InputConfigVM) -> Result<ConfigVM, Error> {
let user_space_size = parse_memory_size(&input.user_space_size)?;
Ok(ConfigVM { user_space_size })
}
}
impl ConfigProcess {
fn from_input(input: &InputConfigProcess) -> Result<ConfigProcess, Error> {
let default_stack_size = parse_memory_size(&input.default_stack_size)?;
let default_heap_size = parse_memory_size(&input.default_heap_size)?;
let default_mmap_size = parse_memory_size(&input.default_mmap_size)?;
Ok(ConfigProcess {
default_stack_size,
default_heap_size,
default_mmap_size,
})
}
}
impl ConfigMount {
fn from_input(input: &InputConfigMount) -> Result<ConfigMount, Error> {
const ALL_FS_TYPES : [&str; 3] = [ "sefs", "hostfs", "ramfs" ];
let type_ = {
let type_ = input.type_.to_string();
if !ALL_FS_TYPES.contains(&type_.as_str()) {
return errno!(EINVAL, "Unsupported file system type");
}
type_
};
let target = {
let target = input.target.clone();
if !target.starts_with("/") {
return errno!(EINVAL, "Target must be an absolute path");
}
target
};
let source = input.source.clone();
let options = ConfigMountOptions::from_input(&input.options)?;
Ok(ConfigMount { type_, target, source, options, })
}
}
impl ConfigMountOptions {
fn from_input(input: &InputConfigMountOptions) -> Result<ConfigMountOptions, Error> {
let (integrity_only, mac) =
if !input.integrity_only {
(false, None)
} else {
if input.mac.is_none() {
return errno!(EINVAL, "MAC is expected");
}
(true, input.mac.clone())
};
Ok(ConfigMountOptions { integrity_only, mac })
}
}
fn parse_memory_size(mem_str: &str) -> Result<usize, Error> {
const UNIT2FACTOR : [(&str, usize); 5]= [
("KB", 1024),
("MB", 1024 * 1024),
("GB", 1024 * 1024 * 1024),
("TB", 1024 * 1024 * 1024 * 1024),
("B", 1),
];
let mem_str = mem_str.trim();
let (unit, factor) = UNIT2FACTOR
.iter()
.position(|(unit, _)| mem_str.ends_with(unit))
.ok_or_else(|| Error::new(Errno::EINVAL, "No unit"))
.map(|unit_i| &UNIT2FACTOR[unit_i])?;
let number =
match mem_str[0..mem_str.len() - unit.len()]
.trim()
.parse::<usize>()
{
Err(_) => return errno!(EINVAL, "No number"),
Ok(number) => number
};
Ok(number * factor)
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct InputConfig {
#[serde(default)]
pub vm: InputConfigVM,
#[serde(default)]
pub process: InputConfigProcess,
#[serde(default)]
pub mount: Vec<InputConfigMount>,
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct InputConfigVM {
#[serde(default = "InputConfigVM::get_user_space_size")]
pub user_space_size : String,
}
impl InputConfigVM {
fn get_user_space_size() -> String {
"128MB".to_string()
}
}
impl Default for InputConfigVM {
fn default() -> InputConfigVM {
InputConfigVM {
user_space_size: InputConfigVM::get_user_space_size()
}
}
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct InputConfigProcess {
#[serde(default = "InputConfigProcess::get_default_stack_size")]
pub default_stack_size: String,
#[serde(default = "InputConfigProcess::get_default_heap_size")]
pub default_heap_size: String,
#[serde(default = "InputConfigProcess::get_default_mmap_size")]
pub default_mmap_size: String,
}
impl InputConfigProcess {
fn get_default_stack_size() -> String {
"8MB".to_string()
}
fn get_default_heap_size() -> String {
"16MB".to_string()
}
fn get_default_mmap_size() -> String {
"32MB".to_string()
}
}
impl Default for InputConfigProcess {
fn default() -> InputConfigProcess {
InputConfigProcess {
default_stack_size: InputConfigProcess::get_default_stack_size(),
default_heap_size: InputConfigProcess::get_default_heap_size(),
default_mmap_size: InputConfigProcess::get_default_mmap_size(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct InputConfigMount {
#[serde(rename = "type")]
pub type_: String,
pub target: String,
pub source: Option<String>,
#[serde(default)]
pub options: InputConfigMountOptions,
}
#[derive(Deserialize, Debug, Default)]
#[serde(deny_unknown_fields)]
struct InputConfigMountOptions {
#[serde(default)]
pub integrity_only: bool,
#[serde(rename = "MAC")]
#[serde(default)]
pub mac: Option<String>,
}

@ -28,6 +28,8 @@ extern crate rcore_fs_ramfs;
extern crate rcore_fs_mountfs;
#[macro_use]
extern crate derive_builder;
extern crate serde;
extern crate serde_json;
use sgx_trts::libc;
use sgx_types::*;
@ -37,8 +39,9 @@ use std::panic;
#[macro_use]
mod prelude;
mod entry;
mod errno;
mod entry;
mod config;
mod fs;
mod misc;
mod process;

@ -21,7 +21,7 @@ pub use std::fmt::{Debug, Display};
pub use std::io::{Read, Seek, SeekFrom, Write};
pub use std::iter::Iterator;
pub use std::rc::Rc;
pub use std::string::String;
pub use std::string::{String, ToString};
pub use std::vec::Vec;
pub use errno::Errno;

@ -1,6 +1,7 @@
use super::*;
use super::vm_manager::{VMRange, VMManager, VMMapOptionsBuilder, VMMapOptions, VMMapAddr, VMInitializer};
use super::user_space_vm::{UserSpaceVMManager, UserSpaceVMRange, USER_SPACE_VM_MANAGER};
use super::super::config;
use std::slice;
@ -25,10 +26,6 @@ macro_rules! impl_setter_for_process_vm_builder {
}
impl ProcessVMBuilder {
pub const DEFAULT_STACK_SIZE: usize = 1 * 1024 * 1024;
pub const DEFAULT_HEAP_SIZE: usize = 16 * 1024 * 1024;
pub const DEFAULT_MMAP_SIZE: usize = 16 * 1024 * 1024;
pub fn new(code_size: usize, data_size: usize) -> ProcessVMBuilder {
ProcessVMBuilder {
code_size,
@ -50,9 +47,12 @@ impl ProcessVMBuilder {
let data_size = self.data_size;
let ldso_code_size = self.ldso_code_size.unwrap_or(0);
let ldso_data_size = self.ldso_data_size.unwrap_or(0);
let heap_size = self.heap_size.unwrap_or(ProcessVMBuilder::DEFAULT_HEAP_SIZE);
let stack_size = self.stack_size.unwrap_or(ProcessVMBuilder::DEFAULT_STACK_SIZE);
let mmap_size = self.mmap_size.unwrap_or(ProcessVMBuilder::DEFAULT_MMAP_SIZE);
let heap_size = self.heap_size.unwrap_or(
config::LIBOS_CONFIG.process.default_heap_size);
let stack_size = self.stack_size.unwrap_or(
config::LIBOS_CONFIG.process.default_stack_size);
let mmap_size = self.mmap_size.unwrap_or(
config::LIBOS_CONFIG.process.default_mmap_size);
let range_sizes = vec![
code_size, data_size,
ldso_code_size, ldso_data_size,

@ -41,7 +41,7 @@ lazy_static! {
let (addr, size) = {
let mut addr: usize = 0;
let mut size: usize = 0;
unsafe { vm_get_prealloced_data_space(&mut addr, &mut size) };
unsafe { vm_get_preallocated_user_space_memory(&mut addr, &mut size) };
(addr, size)
};
let user_space_vm_manager = unsafe {
@ -55,7 +55,7 @@ lazy_static! {
}
extern "C" {
pub fn vm_get_prealloced_data_space(addr: &mut usize, size: &mut usize);
pub fn vm_get_preallocated_user_space_memory(addr: &mut usize, size: &mut usize);
}

@ -1,13 +0,0 @@
#include <stddef.h>
#define DATA_SPACE_SIZE (128*1024*1024)
static char __prealloced_data_space[DATA_SPACE_SIZE]
__attribute__ ((
section(".exectuable_data,\"awx\",@nobits#"),
aligned(4096))) = {0};
void vm_get_prealloced_data_space(void** paddr, size_t* psize) {
*paddr = __prealloced_data_space;
*psize = DATA_SPACE_SIZE;
}

@ -36,7 +36,7 @@ SEFS_PATH := sefs
all: build
build: $(BUILD_TARGETS) sefs
build: $(BUILD_TARGETS) sefs libocclum.signed.so
$(BUILD_TARGETS): %:
@$(ECHO) "$(CYAN)BUILD TEST => $@$(NO_COLOR)"
@ -57,6 +57,9 @@ sefs:
zip
@echo "SEFS => $@"
libocclum.signed.so: Occlum.json Enclave_config.xml Enclave_private.pem
@$(PROJECT_DIR)/tools/bin/build-enclave Occlum.json Enclave_config.xml Enclave_private.pem
#############################################################################
# Test targets
#############################################################################
@ -66,9 +69,6 @@ test: build $(TEST_TARGETS)
pal: $(PROJECT_DIR)/src/pal/pal
@cp $< pal
libocclum.signed.so: $(PROJECT_DIR)/src/libos/libocclum.signed.so
@cp $< libocclum.signed.so
$(TEST_TARGETS): test-%: % pal libocclum.signed.so
@$(ECHO) "$(CYAN)RUN TEST => $<$(NO_COLOR)"
@$(MAKE) --no-print-directory -C $< test ; \
@ -98,7 +98,7 @@ $(BENCH_TARGETS): bench-%: % pal libocclum.signed.so
#############################################################################
clean: $(CLEAN_TARGETS)
@$(RM) -f pal libocclum.signed.so
@$(RM) -f pal libocclum.signed.so Occlum.json.protected
@$(RM) -rf $(FS_PATH) $(SEFS_PATH)
$(CLEAN_TARGETS): clean-%:

35
test/Occlum.json Normal file

@ -0,0 +1,35 @@
{
"vm": {
"user_space_size": "128MB"
},
"process": {
"default_stack_size": "4MB",
"default_heap_size": "16MB",
"default_mmap_size": "32MB"
},
"mount": [
{
"target": "/",
"type": "sefs",
"source": "./root_sefs"
},
{
"target": "/bin",
"type": "sefs",
"source": "./bin_sefs",
"options": {
"integrity_only": true,
"MAC": "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-"
}
},
{
"target": "/host",
"type": "hostfs",
"source": "."
},
{
"target": "/tmp",
"type": "ramfs"
}
]
}

1
tools/bin/.gitignore vendored Normal file

@ -0,0 +1 @@
protect-integrity

93
tools/bin/build-enclave Executable file

@ -0,0 +1,93 @@
#!/bin/bash
working_dir=`pwd`
this_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
project_dir="$( cd "$( dirname "$this_dir/../../../" )" >/dev/null 2>&1 && pwd )"
SGX_SDK="${SGX_SDK:-/opt/intel/sgxsdk}"
occlum_conf_json_path=$1
enclave_conf_xml_path=$2
enclave_key_pem_path=$3
protected_occlum_conf_json_path=`basename $occlum_conf_json_path`".protected"
occlum_conf_file_mac=
occlum_user_space_size=
report_arg_error() {
echo $1
echo ""
echo "Usage: occlum-build-enclave Occlum.json Enclave.xml Enclave.pem"
}
protect_occlum_json() {
cd $working_dir
"$project_dir/tools/bin/protect-integrity" protect $occlum_conf_json_path
}
print_occlum_conf_file_mac() {
cd $working_dir
"$project_dir/tools/bin/protect-integrity" show-mac $protected_occlum_conf_json_path
}
print_occlum_user_space_size() {
cd $working_dir
local size_with_unit=`cat $occlum_conf_json_path | \
python -c "import sys, json; print json.load(sys.stdin)['vm']['user_space_size']"`
numfmt --from=iec ${size_with_unit::-1}
}
build_enclave_so() {
cd $project_dir/src/libos/
make clean-builtin
make
}
sign_enclave_so() {
cd $working_dir
rm -f libocclum.signed.so
local enclave_so_path="$project_dir/src/libos/libocclum.so"
$SGX_SDK/bin/x64/sgx_sign sign \
-key $enclave_key_pem_path \
-enclave $enclave_so_path \
-out "libocclum.signed.so" \
-config $enclave_conf_xml_path
}
# ===========================================================================
# Parse input arguments
# ===========================================================================
if [[ $occlum_conf_json_path != *.json ]] ; then
report_arg_error "Error: Expect a JSON file as the first argument!"
exit -1
fi
if [[ $enclave_conf_xml_path != *.xml ]] ; then
report_arg_error "Error: Expect a XML file as the second argument!"
exit -1
fi
if [[ $enclave_key_pem_path != *.pem ]] ; then
report_arg_error "Error: Expect a PEM file as the third argument!"
exit -1
fi
# ===========================================================================
# Build Occlum.json.protected and libocclum.signed.so
# ===========================================================================
set -e
protect_occlum_json
echo "GEN => $protected_occlum_conf_json_path"
export OCCLUM_BUILTIN_CONF_FILE_MAC=`print_occlum_conf_file_mac`
echo "EXPORT => OCCLUM_BUILTIN_CONF_FILE_MAC = $OCCLUM_BUILTIN_CONF_FILE_MAC"
export OCCLUM_BUILTIN_VM_USER_SPACE_SIZE=`print_occlum_user_space_size`
echo "EXPORT => OCCLUM_BUILTIN_VM_USER_SPACE_SIZE = $OCCLUM_BUILTIN_VM_USER_SPACE_SIZE"
build_enclave_so
sign_enclave_so
echo "SIGN => libocclum.signed.so"

5
tools/protect-integrity/.gitignore vendored Normal file

@ -0,0 +1,5 @@
protect-integrity
App/Enclave_u.h
App/Enclave_u.c
Enclave/Enclave_t.h
Enclave/Enclave_t.c

@ -0,0 +1,356 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <libgen.h>
#include <pwd.h>
#include <sgx_urts.h>
#include <sgx_error.h>
#include <sgx_eid.h>
#include "Enclave_u.h"
#define MAX_PATH FILENAME_MAX
#define TOKEN_FILENAME "enclave.token"
#define ENCLAVE_FILENAME "protect-integrity-enclave.signed.so"
// ==========================================================================
// Enclave Initialization
// ==========================================================================
/* Global EID shared by multiple threads */
static sgx_enclave_id_t global_eid = 0;
typedef struct _sgx_errlist_t {
sgx_status_t err;
const char *msg;
const char *sug; /* Suggestion */
} sgx_errlist_t;
#define REPEATS 500000
/* Error code returned by sgx_create_enclave */
static sgx_errlist_t sgx_errlist[] = {
{
SGX_ERROR_UNEXPECTED,
"Unexpected error occurred.",
NULL
},
{
SGX_ERROR_INVALID_PARAMETER,
"Invalid parameter.",
NULL
},
{
SGX_ERROR_OUT_OF_MEMORY,
"Out of memory.",
NULL
},
{
SGX_ERROR_ENCLAVE_LOST,
"Power transition occurred.",
"Please refer to the sample \"PowerTransition\" for details."
},
{
SGX_ERROR_INVALID_ENCLAVE,
"Invalid enclave image.",
NULL
},
{
SGX_ERROR_INVALID_ENCLAVE_ID,
"Invalid enclave identification.",
NULL
},
{
SGX_ERROR_INVALID_SIGNATURE,
"Invalid enclave signature.",
NULL
},
{
SGX_ERROR_OUT_OF_EPC,
"Out of EPC memory.",
NULL
},
{
SGX_ERROR_NO_DEVICE,
"Invalid SGX device.",
"Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards."
},
{
SGX_ERROR_MEMORY_MAP_CONFLICT,
"Memory map conflicted.",
NULL
},
{
SGX_ERROR_INVALID_METADATA,
"Invalid enclave metadata.",
NULL
},
{
SGX_ERROR_DEVICE_BUSY,
"SGX device was busy.",
NULL
},
{
SGX_ERROR_INVALID_VERSION,
"Enclave version was invalid.",
NULL
},
{
SGX_ERROR_INVALID_ATTRIBUTE,
"Enclave was not authorized.",
NULL
},
{
SGX_ERROR_ENCLAVE_FILE_ACCESS,
"Can't open enclave file.",
NULL
},
};
/* Check error conditions for loading enclave */
static void print_error_message(sgx_status_t ret)
{
size_t idx = 0;
size_t ttl = sizeof sgx_errlist/sizeof sgx_errlist[0];
for (idx = 0; idx < ttl; idx++) {
if(ret == sgx_errlist[idx].err) {
if(NULL != sgx_errlist[idx].sug)
printf("Info: %s\n", sgx_errlist[idx].sug);
printf("Error: %s\n", sgx_errlist[idx].msg);
break;
}
}
if (idx == ttl)
printf("Error: Unexpected error occurred.\n");
}
static const char* get_enclave_absolute_path() {
static char enclave_path[MAX_PATH] = {0};
// Get the absolute path of the executable
readlink("/proc/self/exe", enclave_path, sizeof(enclave_path));
// Get the absolute path of the containing directory
dirname(enclave_path);
// Get the absolute path of the enclave
strncat(enclave_path, "/", sizeof(enclave_path));
strncat(enclave_path, ENCLAVE_FILENAME, sizeof(enclave_path));
return (const char*)enclave_path;
}
/* Initialize the enclave:
* Step 1: try to retrieve the launch token saved by last transaction
* Step 2: call sgx_create_enclave to initialize an enclave instance
* Step 3: save the launch token if it is updated
*/
static int initialize_enclave(void)
{
char token_path[MAX_PATH] = {'\0'};
sgx_launch_token_t token = {0};
sgx_status_t ret = SGX_ERROR_UNEXPECTED;
int updated = 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 */
const char *home_dir = getpwuid(getuid())->pw_dir;
if (home_dir != NULL &&
(strlen(home_dir)+strlen("/")+sizeof(TOKEN_FILENAME)+1) <= MAX_PATH) {
/* compose the token path */
strncpy(token_path, home_dir, strlen(home_dir));
strncat(token_path, "/", strlen("/"));
strncat(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME)+1);
} else {
/* if token path is too long or $HOME is NULL */
strncpy(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME));
}
FILE *fp = fopen(token_path, "rb");
if (fp == NULL && (fp = fopen(token_path, "wb")) == NULL) {
printf("Warning: Failed to create/open the launch token file \"%s\".\n", token_path);
}
if (fp != NULL) {
/* read the token from saved file */
size_t read_num = fread(token, 1, sizeof(sgx_launch_token_t), fp);
if (read_num != 0 && read_num != sizeof(sgx_launch_token_t)) {
/* if token is invalid, clear the buffer */
memset(&token, 0x0, sizeof(sgx_launch_token_t));
printf("Warning: Invalid launch token read from \"%s\".\n", token_path);
}
}
/* Step 2: call sgx_create_enclave to initialize an enclave instance */
/* Debug Support: set 2nd parameter to 1 */
const char* enclave_path = get_enclave_absolute_path();
ret = sgx_create_enclave(enclave_path, SGX_DEBUG_FLAG, &token, &updated, &global_eid, NULL);
if (ret != SGX_SUCCESS) {
print_error_message(ret);
if (fp != NULL) fclose(fp);
return -1;
}
/* Step 3: save the launch token if it is updated */
if (updated == 0 || fp == NULL) {
/* if the token is not updated, or file handler is invalid, do not perform saving */
if (fp != NULL) fclose(fp);
return 0;
}
/* reopen the file with write capablity */
fp = freopen(token_path, "wb", fp);
if (fp == NULL) return 0;
size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp);
if (write_num != sizeof(sgx_launch_token_t))
printf("Warning: Failed to save launch token to \"%s\".\n", token_path);
fclose(fp);
return 0;
}
// ==========================================================================
// OCalls
// ==========================================================================
void ocall_print(const char *str) {
printf("%s", str);
}
void ocall_eprint(const char *str) {
fprintf(stderr, "%s", str);
}
int ocall_open(const char* path) {
return open(path, O_RDONLY);
}
ssize_t ocall_read(int fd, void* buf, size_t size) {
return read(fd, buf, size);
}
ssize_t ocall_write(int fd, const void* buf, size_t size) {
return write(fd, buf, size);
}
int ocall_close(int fd) {
return close(fd);
}
// ==========================================================================
// Parsing program arguments
// ==========================================================================
static void print_help(void) {
fprintf(stderr,
"Error: invalid arguments\n"
"\n"
"Usage:\n"
"\tprotect-integrity protect <ordinary_file>\n"
"\tprotect-integrity show <protected_file>\n"
"\tprotect-integrity show-mac <protected_file>\n");
}
#define CMD_ERROR (-1)
#define CMD_PROTECT 0
#define CMD_SHOW 1
#define CMD_SHOW_MAC 2
static int parse_args(
/* inputs */
int argc,
char* argv[],
/* outputs */
int* arg_command,
char** arg_file_path)
{
if (argc != 3) return -1;
if (strcmp(argv[1], "protect") == 0) {
*arg_command = CMD_PROTECT;
}
else if (strcmp(argv[1], "show") == 0) {
*arg_command = CMD_SHOW;
}
else if (strcmp(argv[1], "show-mac") == 0) {
*arg_command = CMD_SHOW_MAC;
}
else {
return -1;
}
*arg_file_path = argv[2];
return 0;
}
// ==========================================================================
// Main
// ==========================================================================
int SGX_CDECL main(int argc, char *argv[]) {
/* Parse arguments */
int arg_command = CMD_ERROR;
char* arg_file_path = NULL;
if (parse_args(argc, argv, &arg_command, &arg_file_path) < 0) {
print_help();
return -1;
}
/* Initialize the enclave */
if (initialize_enclave() < 0) {
fprintf(stderr, "Error: enclave initialization failed\n");
return -1;
}
/* Do the command */
int ret = 0;
switch(arg_command){
case CMD_PROTECT: {
const char* input_path = arg_file_path;
const char* output_ext = ".protected";
size_t output_path_len = strlen(input_path) + strlen(output_ext) + 1;
char* output_path = (char*) malloc(output_path_len);
strncpy(output_path, input_path, output_path_len);
strncat(output_path, output_ext, output_path_len);
if (ecall_protect(global_eid, &ret, input_path, output_path)) {
fprintf(stderr, "Error: ecall failed\n");
ret = -1;
}
break;
}
case CMD_SHOW: {
const char* input_path = arg_file_path;
if (ecall_show(global_eid, &ret, input_path)) {
fprintf(stderr, "Error: ecall failed\n");
ret = -1;
}
break;
}
case CMD_SHOW_MAC: {
const char* input_path = arg_file_path;
if (ecall_show_mac(global_eid, &ret, input_path)) {
fprintf(stderr, "Error: ecall failed\n");
ret = -1;
}
break;
}
default: {
// This should never happen!
abort();
}
}
/* Destroy the enclave */
sgx_destroy_enclave(global_eid);
return ret;
}

@ -0,0 +1,20 @@
#ifndef _APP_H_
#define _APP_H_
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
extern sgx_enclave_id_t global_eid; /* global enclave id */
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(__cplusplus)
}
#endif
#endif /* !_APP_H_ */

@ -0,0 +1,11 @@
<EnclaveConfiguration>
<ProdID>0</ProdID>
<ISVSVN>0</ISVSVN>
<StackMaxSize>0x40000</StackMaxSize>
<HeapMaxSize>0x100000</HeapMaxSize>
<TCSNum>10</TCSNum>
<TCSPolicy>1</TCSPolicy>
<DisableDebug>0</DisableDebug>
<MiscSelect>0</MiscSelect>
<MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>

@ -0,0 +1,163 @@
#include "Enclave_t.h"
#include <stdio.h>
#include <string.h>
#include <sgx_trts.h>
#include <sgx_tprotected_fs.h>
// ==========================================================================
// Helper functions
// ==========================================================================
#define PRINTF_BUFSIZE 512
static int printf(const char* fmt, ...) {
char buf[PRINTF_BUFSIZE] = {0};
va_list args;
va_start(args, fmt);
vsnprintf(buf, PRINTF_BUFSIZE, fmt, args);
va_end(args);
ocall_print(buf);
return 0;
}
static int eprintf(const char* fmt, ...) {
char buf[PRINTF_BUFSIZE] = {0};
va_list args;
va_start(args, fmt);
vsnprintf(buf, PRINTF_BUFSIZE, fmt, args);
va_end(args);
ocall_eprint(buf);
return 0;
}
static void print_mac(sgx_aes_gcm_128bit_tag_t* mac) {
unsigned char* bytes = (unsigned char*) mac;
for (size_t bi = 0; bi < sizeof(*mac); bi++) {
if (bi != 0) printf("-");
printf("%02x", bytes[bi] & 0xFF);
}
printf("\n");
}
static int open(const char* path) {
int fd = 0;
ocall_open(&fd, path);
return fd;
}
static ssize_t read(int fd, void* buf, size_t size) {
ssize_t ret = 0;
ocall_read(&ret, fd, buf, size);
return ret;
}
static ssize_t write(int fd, const void* buf, size_t size) {
ssize_t ret = 0;
ocall_write(&ret, fd, buf, size);
return ret;
}
static int close(int fd) {
int ret = 0;
ocall_close(&ret, fd);
return ret;
}
// ==========================================================================
// ECalls
// ==========================================================================
int ecall_protect(const char* input_path, const char* output_path) {
int input_file = -1;
SGX_FILE* output_file = NULL;
size_t len;
char buf[4 * 1024];
input_file = open(input_path);
if (input_file < 0) {
eprintf("Error: cannot open the input file at %s\n", input_path);
goto on_error;
}
output_file = sgx_fopen_integrity_only(output_path, "w");
if (output_file == NULL) {
eprintf("Error: cannot create the output file %s\n", output_path);
goto on_error;
}
while ((len = read(input_file, buf, sizeof(buf))) > 0) {
if (sgx_fwrite(buf, 1, len, output_file) != len) {
eprintf("Error: failed to write to the output file %s\n", output_path);
goto on_error;
}
}
close(input_file);
sgx_fclose(output_file);
return 0;
on_error:
if (input_file >= 0) {
close(input_file);
}
if (output_file != NULL) {
sgx_fclose(output_file);
sgx_remove(output_path);
}
return -1;
}
int ecall_show(const char* protected_file_path) {
SGX_FILE* protected_file = NULL;
ssize_t len;
char buf[4 * 1024];
protected_file = sgx_fopen_integrity_only(protected_file_path, "r");
if (protected_file == NULL) {
eprintf("Error: failed to open the given protected file %s\n", protected_file_path);
goto on_error;
}
while ((len = sgx_fread(buf, 1, sizeof(buf), protected_file)) > 0) {
write(1/* stdout */, buf, len);
}
if (sgx_ferror(protected_file)) {
eprintf("Error: failed to read the given protected file %s\n", protected_file_path);
goto on_error;
}
sgx_fclose(protected_file);
return 0;
on_error:
if (protected_file != NULL) {
sgx_fclose(protected_file);
}
return -1;
}
int ecall_show_mac(const char* protected_file_path) {
SGX_FILE* protected_file = NULL;
sgx_aes_gcm_128bit_tag_t mac = { 0 };
protected_file = sgx_fopen_integrity_only(protected_file_path, "r");
if (protected_file == NULL) {
eprintf("Error: failed to open the given protected file %s\n", protected_file_path);
goto on_error;
}
if (sgx_fget_mac(protected_file, &mac)) {
eprintf("Error: failed to get the MAC of the protected file %s\n", protected_file_path);
goto on_error;
}
print_mac(&mac);
sgx_fclose(protected_file);
return 0;
on_error:
if (protected_file != NULL) {
sgx_fclose(protected_file);
}
return -1;
}

@ -0,0 +1,27 @@
enclave {
include "sys/types.h"
include "sgx_key.h"
from "sgx_tstdc.edl" import *;
from "sgx_tprotected_fs.edl" import *;
trusted {
public int ecall_protect([in, string] const char* input_path,
[in, string] const char* ouput_path);
public int ecall_show([in, string] const char* input_path);
public int ecall_show_mac([in, string] const char* input_path);
};
untrusted {
// File operations
int ocall_open([in, string] const char* path);
ssize_t ocall_read(int fd, [out, size=size] void* buf, size_t size);
ssize_t ocall_write(int fd, [in, size=size] const void* buf, size_t size);
int ocall_close(int fd);
// Print to the standard output
void ocall_print([in, string] const char* msg);
// Print to the standard error
void ocall_eprint([in, string] const char* msg);
};
};

@ -0,0 +1,16 @@
#ifndef _ENCLAVE_H_
#define _ENCLAVE_H_
#include <stdlib.h>
#include <assert.h>
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(__cplusplus)
}
#endif
#endif /* !_ENCLAVE_H_ */

@ -0,0 +1,9 @@
enclave.so
{
global:
g_global_data_sim;
g_global_data;
enclave_entry;
local:
*;
};

@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

@ -0,0 +1,204 @@
######## SGX SDK Settings ########
SGX_SDK ?= /opt/intel/sgxsdk
SGX_MODE ?= HW
SGX_ARCH ?= x64
SGX_DEBUG ?= 1
ifeq ($(shell getconf LONG_BIT), 32)
SGX_ARCH := x86
else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32)
SGX_ARCH := x86
endif
ifeq ($(SGX_ARCH), x86)
SGX_COMMON_CFLAGS := -m32
SGX_LIBRARY_PATH := $(SGX_SDK)/lib
SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign
SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r
else
SGX_COMMON_CFLAGS := -m64
SGX_LIBRARY_PATH := $(SGX_SDK)/lib64
SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign
SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r
endif
ifeq ($(SGX_DEBUG), 1)
ifeq ($(SGX_PRERELEASE), 1)
$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!)
endif
endif
SGX_COMMON_CFLAGS += -Wall -Wno-unused-result
ifeq ($(SGX_DEBUG), 1)
SGX_COMMON_CFLAGS += -O2 -g
else
SGX_COMMON_CFLAGS += -O2
endif
######## App Settings ########
ifneq ($(SGX_MODE), HW)
Urts_Library_Name := sgx_urts_sim
else
Urts_Library_Name := sgx_urts
endif
App_Cpp_Files := App/App.cpp
App_Include_Paths := -IInclude -IApp -I$(SGX_SDK)/include
App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths)
# Three configuration modes - Debug, prerelease, release
# Debug - Macro DEBUG enabled.
# Prerelease - Macro NDEBUG and EDEBUG enabled.
# Release - Macro NDEBUG enabled.
ifeq ($(SGX_DEBUG), 1)
App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG
else ifeq ($(SGX_PRERELEASE), 1)
App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG
else
App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG
endif
App_Cpp_Flags := $(App_C_Flags) -std=c++11
App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lsgx_uprotected_fs -lpthread
ifneq ($(SGX_MODE), HW)
App_Link_Flags += -lsgx_uae_service_sim
else
App_Link_Flags += -lsgx_uae_service
endif
App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o)
App_Name := protect-integrity
######## Enclave Settings ########
ifneq ($(SGX_MODE), HW)
Trts_Library_Name := sgx_trts_sim
Service_Library_Name := sgx_tservice_sim
else
Trts_Library_Name := sgx_trts
Service_Library_Name := sgx_tservice
endif
Crypto_Library_Name := sgx_tcrypto
Enclave_Cpp_Files := Enclave/Enclave.cpp
Enclave_C_Files :=
Enclave_Include_Paths := -IInclude -IEnclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport
Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fPIC -fstack-protector $(Enclave_Include_Paths)
Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++03 -nostdinc++
# To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries:
# 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options,
# so that the whole content of trts is included in the enclave.
# 2. For other libraries, you just need to pull the required symbols.
# Use `--start-group' and `--end-group' to link these libraries.
# Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options.
# Otherwise, you may get some undesirable errors.
Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \
-Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \
-Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_tprotected_fs -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \
-Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \
-Wl,-pie,-eenclave_entry -Wl,--export-dynamic \
-Wl,--defsym,__ImageBase=0 \
-Wl,--version-script=Enclave/Enclave.lds
Enclave_Cpp_Objects := $(Enclave_Cpp_Files:.cpp=.o)
Enclave_C_Objects := $(Enclave_C_Files:.c=.o)
Enclave_Name := protect-integrity-enclave.so
Signed_Enclave_Name := protect-integrity-enclave.signed.so
Enclave_Config_File := Enclave/Enclave.config.xml
ifeq ($(SGX_MODE), HW)
ifneq ($(SGX_DEBUG), 1)
ifneq ($(SGX_PRERELEASE), 1)
Build_Mode = HW_RELEASE
endif
endif
endif
.PHONY: all run
ifeq ($(Build_Mode), HW_RELEASE)
all: $(App_Name) $(Enclave_Name)
@echo "The project has been built in release hardware mode."
@echo "Please sign the $(Enclave_Name) first with your signing key before you run the $(App_Name) to launch and access the enclave."
@echo "To sign the enclave use the command:"
@echo " $(SGX_ENCLAVE_SIGNER) sign -key <your key> -enclave $(Enclave_Name) -out <$(Signed_Enclave_Name)> -config $(Enclave_Config_File)"
@echo "You can also sign the enclave using an external signing tool."
@echo "To build the project in simulation mode set SGX_MODE=SIM. To build the project in prerelease mode set SGX_PRERELEASE=1 and SGX_MODE=HW."
else
all: $(App_Name) $(Signed_Enclave_Name)
endif
######## App Objects ########
App/Enclave_u.c: $(SGX_EDGER8R) Enclave/Enclave.edl
@cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include
@echo "GEN => $@"
App/Enclave_u.o: App/Enclave_u.c
@$(CC) $(App_C_Flags) -c $< -o $@
@echo "CC <= $<"
App/%.o: App/%.cpp
@$(CXX) $(App_Cpp_Flags) -c $< -o $@
@echo "CXX <= $<"
$(App_Name): App/Enclave_u.o $(App_Cpp_Objects)
@$(CXX) $^ -o $@ $(App_Link_Flags)
@cp $(App_Name) ../bin/
@echo "LINK => $@"
######## Enclave Objects ########
Enclave/Enclave_t.c: $(SGX_EDGER8R) Enclave/Enclave.edl
@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include
@echo "GEN => $@"
Enclave/Enclave_t.o: Enclave/Enclave_t.c
@$(CC) $(Enclave_C_Flags) -c $< -o $@
@echo "CC <= $<"
$(Enclave_Cpp_Objects): Enclave/%.o: Enclave/%.cpp
@$(CXX) $(Enclave_Cpp_Flags) -c $< -o $@
@echo "CXX <= $<"
$(Enclave_C_Objects): Enclave/%.o: Enclave/%.c
@$(CC) $(Enclave_C_Flags) -c $< -o $@
@echo "CC <= $<"
$(Enclave_Name): Enclave/Enclave_t.o $(Enclave_Cpp_Objects) $(Enclave_C_Objects)
$(CXX) $^ -o $@ $(Enclave_Link_Flags)
@echo "LINK => $@"
$(Signed_Enclave_Name): $(Enclave_Name)
@$(SGX_ENCLAVE_SIGNER) sign -key Enclave/Enclave_private.pem -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File)
@cp $(Signed_Enclave_Name) ../bin/
@echo "SIGN => $@"
.PHONY: test
test: all random.txt
./protect-integrity protect random.txt
./protect-integrity show random.txt.protected > random.txt.unprotected
./protect-integrity show-mac random.txt.protected
diff random.txt random.txt.unprotected
@echo "Pass ^_^"
random.txt:
@base64 /dev/urandom | head -c 10000000 > random.txt
.PHONY: clean
clean:
@rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) $(Enclave_C_Objects) Enclave/Enclave_t.* *.test.txt random.txt*

@ -0,0 +1,37 @@
# protect-integrity
This is a command-line utility that protects the _integrity_ of a file using the _integrity-only_ mode of SGX Protected File System Library.
## Prerequesite
This integrity-only mode is provided by Occlum's fork of Intel SGX SDK, not available on vanilla Intel SGX SDK. So make sure that you have Occlum's fork of Intel SGX SDK installed.
## How to Build
To build the project, run the following command
make
To test the project, run the following command
make test
## How to Use
To protect an ordinary file, run the following command
./protect-integrity protect <ordinary_file>
which will generate a protected file named `<ordinary_file>.protected` in the current working directory. The content of `<ordinary_file>.protected` is the same as `<ordinary_file` but associated with (a tree of) 128-bit MACs to protect its integrity.
To show the content of a protected file, run the following command
./protect-integrity show <protected_file>
To show the (root) MAC of a protected file, run the following command
./protect-integrity show-mac <protected_file>
## Note
This utility is intended to be used in _trusted_ development environment, not _untrusted_ deployment environment.