diff --git a/samplecode/new_helloworld/.cargo/config.toml b/samplecode/new_helloworld/.cargo/config.toml new file mode 100644 index 000000000..f4c2921a7 --- /dev/null +++ b/samplecode/new_helloworld/.cargo/config.toml @@ -0,0 +1,4 @@ +[alias] +xrun = "run --package xtask --" +make = "run --package xtask -- build" +# xbuild = "build --package xtask" diff --git a/samplecode/new_helloworld/Cargo.toml b/samplecode/new_helloworld/Cargo.toml new file mode 100644 index 000000000..001847ffa --- /dev/null +++ b/samplecode/new_helloworld/Cargo.toml @@ -0,0 +1,4 @@ +[workspace] +members = ["app", "enclave", "edl","xtask"] +resolver = "2" + diff --git a/samplecode/new_helloworld/Makefile b/samplecode/new_helloworld/Makefile new file mode 100644 index 000000000..5463449e7 --- /dev/null +++ b/samplecode/new_helloworld/Makefile @@ -0,0 +1,226 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +######## SGX SDK Settings ######## + +SGX_SDK ?= /opt/intel/sgxsdk +SGX_MODE ?= HW +SGX_ARCH ?= x64 + +TOP_DIR := ../.. +include $(TOP_DIR)/buildenv.mk + +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_BIN_PATH := $(SGX_SDK)/bin/x86 +else + SGX_COMMON_CFLAGS := -m64 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 + SGX_BIN_PATH := $(SGX_SDK)/bin/x64 +endif + +ifeq ($(SGX_DEBUG), 1) + SGX_COMMON_CFLAGS += -O0 -g + Rust_Build_Flags := + Rust_Build_Out := debug +else + SGX_COMMON_CFLAGS += -O2 + Rust_Build_Flags := --release + Rust_Build_Out := release +endif + +SGX_EDGER8R := $(SGX_BIN_PATH)/sgx_edger8r +ifneq ($(SGX_MODE), HYPER) + SGX_ENCLAVE_SIGNER := $(SGX_BIN_PATH)/sgx_sign +else + SGX_ENCLAVE_SIGNER := $(SGX_BIN_PATH)/sgx_sign_hyper + SGX_EDGER8R_MODE := --sgx-mode $(SGX_MODE) +endif + +######## CUSTOM Settings ######## + +CUSTOM_LIBRARY_PATH := ./lib +CUSTOM_BIN_PATH := ./bin +CUSTOM_SYSROOT_PATH := ./sysroot +CUSTOM_EDL_PATH := $(ROOT_DIR)/sgx_edl/edl +CUSTOM_COMMON_PATH := $(ROOT_DIR)/common + +######## EDL Settings ######## + +Enclave_EDL_Files := enclave/enclave_t.c enclave/enclave_t.h app/enclave_u.c app/enclave_u.h + +######## APP Settings ######## + +App_Rust_Flags := $(Rust_Build_Flags) +App_Src_Files := $(shell find app/ -type f -name '*.rs') $(shell find app/ -type f -name 'Cargo.toml') +App_Include_Paths := -I ./app -I$(SGX_SDK)/include -I$(CUSTOM_COMMON_PATH)/inc -I$(CUSTOM_EDL_PATH) +App_C_Flags := $(CFLAGS) $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) + +App_Rust_Path := ./target/$(Rust_Build_Out) +App_Enclave_u_Object := $(CUSTOM_LIBRARY_PATH)/libenclave_u.a +App_Name := $(CUSTOM_BIN_PATH)/app + +######## Enclave Settings ######## + +# BUILD_STD=no use no_std +# BUILD_STD=cargo use cargo-std-aware +# BUILD_STD=xargo use xargo +# BUILD_STD ?= cargo + +Rust_Build_Target := x86_64-unknown-linux-sgx +Rust_Target_Path := $(ROOT_DIR)/rustlib + +Rust_Build_Std := $(Rust_Build_Flags) -Zbuild-std=core,alloc +Rust_Std_Features := +Rust_Target_Flags := --target $(Rust_Target_Path)/$(Rust_Build_Target).json +Rust_Sysroot_Path := $(CURDIR)/sysroot +Rust_Sysroot_Flags := RUSTFLAGS="--sysroot $(Rust_Sysroot_Path)" + +RustEnclave_Build_Flags := $(Rust_Build_Flags) +RustEnclave_Src_Files := $(shell find enclave/ -type f -name '*.rs') $(shell find enclave/ -type f -name 'Cargo.toml') +RustEnclave_Include_Paths := -I$(CUSTOM_COMMON_PATH)/inc -I$(CUSTOM_COMMON_PATH)/inc/tlibc -I$(CUSTOM_EDL_PATH) + +RustEnclave_Link_Libs := -L$(CUSTOM_LIBRARY_PATH) -lenclave +RustEnclave_C_Flags := $(CFLAGS) $(ENCLAVE_CFLAGS) $(SGX_COMMON_CFLAGS) $(RustEnclave_Include_Paths) +RustEnclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ + -Wl,--start-group $(RustEnclave_Link_Libs) -Wl,--end-group \ + -Wl,--version-script=enclave/enclave.lds \ + $(ENCLAVE_LDFLAGS) + +# RustEnclave_Out_Path := ./enclave/target/$(Rust_Build_Target)/$(Rust_Build_Out) +# RustEnclave_Out_Path := ./enclave/target/$(Rust_Build_Out) +RustEnclave_Out_Path := ./target/$(Rust_Build_Out) +Rust_Out_Path := ./target/$(Rust_Build_Target)/$(Rust_Build_Out) + +RustEnclave_Lib_Name := $(RustEnclave_Out_Path)/libenclave.a +# RustEnclave_Lib_Name := $(Rust_Out_Path)/libenclave.a +RustEnclave_Name := $(CUSTOM_BIN_PATH)/enclave.so +RustEnclave_Signed_Name := $(CUSTOM_BIN_PATH)/enclave.signed.so + +.PHONY: all +# all: $(RustEnclave_Signed_Name) +all: app enclave sign + +######## EDL Objects ######## + + +$(Enclave_EDL_Files): $(SGX_EDGER8R) edl/enclave.edl + $(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --trusted edl/enclave.edl --search-path $(CUSTOM_COMMON_PATH)/inc --search-path $(CUSTOM_EDL_PATH) --trusted-dir enclave + $(SGX_EDGER8R) $(SGX_EDGER8R_MODE) --untrusted edl/enclave.edl --search-path $(CUSTOM_COMMON_PATH)/inc --search-path $(CUSTOM_EDL_PATH) --untrusted-dir app + @echo "GEN => $(Enclave_EDL_Files)" + +######## App Objects ######## + +# SYMBOLS := $(shell nm $@ | awk '$$2 == "t" && $$3 ~ /^enclave_.*_ocall$$/ {print $$3}') + +app/enclave_u.o: $(Enclave_EDL_Files) + @$(CC) $(App_C_Flags) -c app/enclave_u.c -o $@ + @$(OBJCOPY) --strip-symbol=ocall_table_enclave $@ $@ + @nm $@ | awk '/enclave_.*_ocall/{print $$3}' | while read sym; do \ + $(OBJCOPY) --globalize-symbol=$$sym $@; \ + done + +$(App_Enclave_u_Object): app/enclave_u.o + @mkdir -p $(CUSTOM_LIBRARY_PATH) + @$(AR) rcsD $@ $^ + +$(App_Name): $(App_Enclave_u_Object) app + @mkdir -p $(CUSTOM_BIN_PATH) + @cp $(App_Rust_Path)/app $(CUSTOM_BIN_PATH)/app + @echo "LINK => $@" + +######## Enclave Objects ######## + + +enclave/enclave_t.o: $(Enclave_EDL_Files) + @$(CC) $(RustEnclave_C_Flags) -c enclave/enclave_t.c -o $@ + # @$(OBJCOPY) --localize-symbol=g_ecall_table --strip-symbol=g_ecall_table $@ $@ + @$(OBJCOPY) --localize-symbol=g_ecall_table --localize-symbol=g_dyn_entry_table $@ $@ + +# $(RustEnclave_Name): enclave/enclave_t.o enclave +$(RustEnclave_Name): enclave/enclave_t.o enclave + @mkdir -p $(CUSTOM_LIBRARY_PATH) + @mkdir -p $(CUSTOM_BIN_PATH) + @cp $(RustEnclave_Lib_Name) $(CUSTOM_LIBRARY_PATH)/libenclave.a + # @$(CXX) -o $@ $(RustEnclave_Link_Flags) + @$(CXX) enclave/enclave_t.o -o $@ $(RustEnclave_Link_Flags) + @echo "LINK => $@" + +$(RustEnclave_Signed_Name): $(RustEnclave_Name) enclave/config.xml + @$(SGX_ENCLAVE_SIGNER) sign -key enclave/private.pem -enclave $(RustEnclave_Name) -out $@ -config enclave/config.xml + @echo "SIGN => $@" + +######## Sign Enclave ######## +.PHONY: enclave/config.xml + @$(SGX_ENCLAVE_SIGNER) sign -key enclave/private.pem -enclave $(RustEnclave_Name) -out $@ -config enclave/config.xml + +######## Build App ######## + +.PHONY: app +app: $(App_Enclave_u_Object) + @cd app && SGX_SDK=$(SGX_SDK) cargo build $(App_Rust_Flags) + @mkdir -p $(CUSTOM_BIN_PATH) + @cp $(App_Rust_Path)/app $(CUSTOM_BIN_PATH)/app + +######## Build Enclave ######## +.PHONY: enclave +enclave: enclave/enclave_t.o + @mkdir -p $(CUSTOM_LIBRARY_PATH) + @mkdir -p $(CUSTOM_BIN_PATH) + @cd enclave && cargo build $(RustEnclave_Build_Flags) + @cp $(RustEnclave_Lib_Name) $(CUSTOM_LIBRARY_PATH)/libenclave.a + $(CXX) enclave/enclave_t.o -o $(RustEnclave_Name) $(RustEnclave_Link_Flags) + @echo "LINK => $@" + + +.PHONY: enclave_std +enclave_std: + @mkdir -p $(CUSTOM_BIN_PATH) + @cd $(Rust_Target_Path)/std && cargo build $(Rust_Build_Std) $(Rust_Target_Flags) $(Rust_Std_Features) + + @rm -rf $(Rust_Sysroot_Path) + @mkdir -p $(Rust_Sysroot_Path)/lib/rustlib/$(Rust_Build_Target)/lib + @cp -r $(Rust_Target_Path)/std/target/$(Rust_Build_Target)/$(Rust_Build_Out)/deps/* $(Rust_Sysroot_Path)/lib/rustlib/$(Rust_Build_Target)/lib + + @cd enclave && $(Rust_Sysroot_Flags) cargo build $(Rust_Target_Flags) $(RustEnclave_Build_Flags) + + +######## Sign Enclave ######## +sign: enclave/config.xml + @$(SGX_ENCLAVE_SIGNER) sign -key enclave/private.pem -enclave $(RustEnclave_Name) -out $(RustEnclave_Signed_Name) -config enclave/config.xml + +######## Run Enclave ######## + +.PHONY: run +run: $(App_Name) $(RustEnclave_Signed_Name) + @echo -e '\n===== Run Enclave =====\n' + @cd bin && ./app + +.PHONY: clean +clean: + @rm -f $(App_Name) $(RustEnclave_Name) $(RustEnclave_Signed_Name) enclave/*_t.* app/*_u.* + @cd enclave && cargo clean + @cd app && cargo clean + @cd $(Rust_Target_Path)/std && cargo clean + @rm -rf $(CUSTOM_BIN_PATH) $(CUSTOM_LIBRARY_PATH) $(CUSTOM_SYSROOT_PATH) diff --git a/samplecode/new_helloworld/README.md b/samplecode/new_helloworld/README.md new file mode 100644 index 000000000..f7dc09144 --- /dev/null +++ b/samplecode/new_helloworld/README.md @@ -0,0 +1,6 @@ + + +``` +cargo run --package xtask build +cargo run --package xtask clean +``` \ No newline at end of file diff --git a/samplecode/new_helloworld/app/Cargo.toml b/samplecode/new_helloworld/app/Cargo.toml new file mode 100644 index 000000000..4e5614e71 --- /dev/null +++ b/samplecode/new_helloworld/app/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "app" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +edl = { path = "../edl", default-features = false, features = ["app"] } +sgx_new_edl = { path = "../../../sgx_new_edl", default-features = false, features = [ + "app", +] } +sgx_types = { path = "../../../sgx_types" } +sgx_urts = { path = "../../../sgx_urts" } diff --git a/samplecode/new_helloworld/app/build.rs b/samplecode/new_helloworld/app/build.rs new file mode 100644 index 000000000..fad04484c --- /dev/null +++ b/samplecode/new_helloworld/app/build.rs @@ -0,0 +1,22 @@ +use std::env; + +fn main() { + println!("cargo:rerun-if-env-changed=SGX_MODE"); + println!("cargo:rerun-if-changed=build.rs"); + + let sdk_dir = env::var("SGX_SDK").unwrap_or_else(|_| "/opt/intel/sgxsdk".to_string()); + let mode = env::var("SGX_MODE").unwrap_or_else(|_| "HW".to_string()); + + // let pwd = env::current_dir().unwrap(); + // println!("cargo:rustc-link-search=native={}/../lib", pwd.display()); + // println!("cargo:rustc-link-lib=static=enclave_u"); + + println!("cargo:rustc-link-search=native={}/lib64", sdk_dir); + + match mode.as_ref() { + "SIM" | "SW" => println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"), + "HYPER" => println!("cargo:rustc-link-lib=dylib=sgx_urts_hyper"), + "HW" => println!("cargo:rustc-link-lib=dylib=sgx_urts"), + _ => println!("cargo:rustc-link-lib=dylib=sgx_urts"), + } +} diff --git a/samplecode/new_helloworld/app/src/main.rs b/samplecode/new_helloworld/app/src/main.rs new file mode 100644 index 000000000..8e53fcd63 --- /dev/null +++ b/samplecode/new_helloworld/app/src/main.rs @@ -0,0 +1,57 @@ +use edl::ecalls; +use sgx_new_edl::{ocall, In, Out}; + +extern crate sgx_types; +extern crate sgx_urts; + +use edl::ocalls; +use sgx_types::error::SgxStatus; +use sgx_types::types::*; +use sgx_urts::enclave::SgxEnclave; + +static ENCLAVE_FILE: &str = "enclave.signed.so"; + +fn main() { + let enclave = match SgxEnclave::create(ENCLAVE_FILE, true) { + Ok(enclave) => { + println!("[+] Init Enclave Successful {}!", enclave.eid()); + enclave + } + Err(err) => { + println!("[-] Init Enclave Failed {}!", err.as_str()); + return; + } + }; + + let input_string = String::from("This is a normal world string passed into Enclave!\n"); + let mut retval = SgxStatus::Success; + + let a1 = String::new(); + let a1 = In::new(&a1); + let mut o1 = String::with_capacity(100); + o1.push_str("Hello "); + let arg0 = Out::new(&mut o1); + + let res = ecalls::foo::ecall(enclave.eid(), arg0); + println!("res: {}", res); + println!("o1: {}", o1); + + // let result = unsafe { + // say_something( + // enclave.eid(), + // &mut retval, + // input_string.as_ptr() as *const u8, + // input_string.len(), + // ) + // }; + // match result { + // SgxStatus::Success => println!("[+] ECall Success..."), + // _ => println!("[-] ECall Enclave Failed {}!", result.as_str()), + // } +} + +#[ocall] +fn bar(arg0: In<'_, String>) -> SgxStatus { + println!("bar: {}", arg0.get()); + SgxStatus::Success +} diff --git a/samplecode/new_helloworld/edl/Cargo.toml b/samplecode/new_helloworld/edl/Cargo.toml new file mode 100644 index 000000000..a92fe61ad --- /dev/null +++ b/samplecode/new_helloworld/edl/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "edl" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +# crate-type = ["staticlib", "cdylib"] + +[features] +default = ["enclave", "app"] +enclave = ["sgx_tstd", "sgx_new_edl/enclave"] +app = ["sgx_new_edl/app"] + +[dependencies] +sgx_new_edl = { path = "../../../sgx_new_edl", default-features = false } +sgx_types = { path = "../../../sgx_types" } +sgx_tstd = { path = "../../../sgx_tstd", optional = true } diff --git a/samplecode/new_helloworld/edl/build.rs b/samplecode/new_helloworld/edl/build.rs new file mode 100644 index 000000000..d0152ded1 --- /dev/null +++ b/samplecode/new_helloworld/edl/build.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + let pwd = env::current_dir().unwrap(); + println!("cargo:rustc-link-search=native={}/../lib", pwd.display()); + println!("cargo:rustc-link-lib=static=enclave_u"); +} diff --git a/samplecode/new_helloworld/edl/enclave.edl b/samplecode/new_helloworld/edl/enclave.edl new file mode 100644 index 000000000..1fdb1ba47 --- /dev/null +++ b/samplecode/new_helloworld/edl/enclave.edl @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +enclave { + from "sgx_stdio.edl" import *; + from "sgx_tstd.edl" import *; + + trusted { + public sgx_status_t __do_nothing(); + }; +}; diff --git a/samplecode/new_helloworld/edl/src/ecalls.rs b/samplecode/new_helloworld/edl/src/ecalls.rs new file mode 100644 index 000000000..9837c8a52 --- /dev/null +++ b/samplecode/new_helloworld/edl/src/ecalls.rs @@ -0,0 +1,10 @@ +use sgx_new_edl::{ecalls, In, Out}; +use sgx_types::error::SgxStatus; + +ecalls! { + fn foo(s: Out<'_, String>) -> SgxStatus; +} + +// extern "Rust" { +// fn foo(a: In<'_, String>, b: Out<'_, String>) -> SgxStatus; +// } diff --git a/samplecode/new_helloworld/edl/src/lib.rs b/samplecode/new_helloworld/edl/src/lib.rs new file mode 100644 index 000000000..50902dcfb --- /dev/null +++ b/samplecode/new_helloworld/edl/src/lib.rs @@ -0,0 +1,8 @@ +#![cfg_attr(all(not(target_vendor = "teaclave"), feature = "enclave"), no_std)] + +#[cfg(not(target_vendor = "teaclave"))] +#[cfg(not(feature = "app"))] +extern crate sgx_tstd as std; + +pub mod ecalls; +pub mod ocalls; diff --git a/samplecode/new_helloworld/edl/src/ocalls.rs b/samplecode/new_helloworld/edl/src/ocalls.rs new file mode 100644 index 000000000..7433c9068 --- /dev/null +++ b/samplecode/new_helloworld/edl/src/ocalls.rs @@ -0,0 +1,95 @@ +use core::ffi::{c_int, c_void}; +use sgx_new_edl::{ocalls, In, Out}; +use sgx_types::{error::SgxStatus, types::timespec}; +use std::string::String; + +ocalls! { + #[no_impl] + pub fn u_read_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_pread64_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_write_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_pwrite64_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_sendfile_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_copy_file_range_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_splice_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_fcntl_arg0_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_fcntl_arg1_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_ioctl_arg0_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_ioctl_arg1_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_close_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_isatty_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_dup_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_eventfd_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_futimens_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_malloc_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_free_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_mmap_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_munmap_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_msync_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_mprotect_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_read_hostbuf_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_write_hostbuf_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_thread_set_event_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_thread_wait_event_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_thread_set_multiple_events_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_thread_setwait_events_ocall() -> SgxStatus; + + #[no_impl] + pub fn u_clock_gettime_ocall() -> SgxStatus; + + pub fn bar(arg0: In<'_, String>) -> SgxStatus; +} diff --git a/samplecode/new_helloworld/enclave/Cargo.toml b/samplecode/new_helloworld/enclave/Cargo.toml new file mode 100644 index 000000000..ecf04d908 --- /dev/null +++ b/samplecode/new_helloworld/enclave/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "enclave" +version = "0.1.0" +edition = "2021" +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["staticlib"] + +[dependencies] +edl = { path = "../edl", default-features = false, features = ["enclave"] } +sgx_new_edl = { path = "../../../sgx_new_edl", default-features = false, features = [ + "enclave", +] } +sgx_types = { path = "../../../sgx_types" } +sgx_tstd = { path = "../../../sgx_tstd" } diff --git a/samplecode/new_helloworld/enclave/build.rs b/samplecode/new_helloworld/enclave/build.rs new file mode 100644 index 000000000..e21ffbfc0 --- /dev/null +++ b/samplecode/new_helloworld/enclave/build.rs @@ -0,0 +1,4 @@ +use std::env; +use std::process::Command; + +fn main() {} diff --git a/samplecode/new_helloworld/enclave/config.xml b/samplecode/new_helloworld/enclave/config.xml new file mode 100644 index 000000000..0cf1f46d9 --- /dev/null +++ b/samplecode/new_helloworld/enclave/config.xml @@ -0,0 +1,31 @@ + + + + 0 + 0 + 0x40000 + 0x100000 + 1 + 0 + 0 + 0 + 0xFFFFFFFF + diff --git a/samplecode/new_helloworld/enclave/enclave.lds b/samplecode/new_helloworld/enclave/enclave.lds new file mode 100644 index 000000000..dff98613e --- /dev/null +++ b/samplecode/new_helloworld/enclave/enclave.lds @@ -0,0 +1,12 @@ +libenclave.so +{ + global: + g_global_data_hyper; + g_global_data_sim; + g_global_data; + enclave_entry; + g_peak_heap_used; + g_peak_rsrv_mem_committed; + local: + *; +}; diff --git a/samplecode/new_helloworld/enclave/private.pem b/samplecode/new_helloworld/enclave/private.pem new file mode 100644 index 000000000..529d07be3 --- /dev/null +++ b/samplecode/new_helloworld/enclave/private.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/samplecode/new_helloworld/enclave/src/lib.rs b/samplecode/new_helloworld/enclave/src/lib.rs new file mode 100644 index 000000000..4af17b4d5 --- /dev/null +++ b/samplecode/new_helloworld/enclave/src/lib.rs @@ -0,0 +1,27 @@ +#![cfg_attr(not(target_vendor = "teaclave"), no_std)] +#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))] + +#[cfg(not(target_vendor = "teaclave"))] +#[macro_use] +extern crate sgx_tstd as std; + +use std::io::{self, Write}; +use std::slice; +use std::string::String; +use std::vec::Vec; + +use sgx_new_edl::{ecall, In, Out}; +use sgx_types::error::SgxStatus; + +extern crate edl; + +#[ecall] +pub fn foo(s: Out<'_, String>) -> SgxStatus { + let mut os = String::from("Enclave Message"); + let arg0 = In::new(&mut os); + let (status, retval) = edl::ocalls::bar::ocall(arg0); + let s = s.get_mut(); + s.push_str(retval.as_str()); + s.push_str(format!("status: {:#x}", status).as_str()); + SgxStatus::Success +} diff --git a/samplecode/new_helloworld/xtask/Cargo.toml b/samplecode/new_helloworld/xtask/Cargo.toml new file mode 100644 index 000000000..e7c70f03e --- /dev/null +++ b/samplecode/new_helloworld/xtask/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "xtask" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "*", features = ["derive"] } +once_cell = "1.20" diff --git a/samplecode/new_helloworld/xtask/src/main.rs b/samplecode/new_helloworld/xtask/src/main.rs new file mode 100644 index 000000000..1d52a7a7d --- /dev/null +++ b/samplecode/new_helloworld/xtask/src/main.rs @@ -0,0 +1,282 @@ +use clap; +use clap::Parser; +use once_cell::sync::Lazy; +use std::env; +use std::fs; +use std::path::Path; +use std::process::Command; + +static RUST_TARGET_PATH: Lazy = Lazy::new(|| { + let root = std::env::var("ROOT_DIR").unwrap(); + format!("{root}/rustlib") +}); +static RUST_BUILD_TARGET: Lazy = Lazy::new(|| "x86_64-unknown-linux-sgx".to_string()); +static RUST_BUILD_STD: Lazy = Lazy::new(|| format!("-Zbuild-std=core,alloc")); +static RUST_TARGET_FLAGS: Lazy = Lazy::new(|| { + format!( + "--target {}/{}.json", + RUST_TARGET_PATH.as_str(), + RUST_BUILD_TARGET.as_str() + ) +}); +static RUST_STD_FEATURES: Lazy = Lazy::new(|| format!("")); +static RUST_SYSROOT_PATH: Lazy = + Lazy::new(|| format!("{}/sysroot", std::env::var("CURDIR").unwrap())); +static RUST_SYSROOT_FLAGS: Lazy = + Lazy::new(|| format!("RUSTFLAGS=\"--sysroot {}\"", RUST_SYSROOT_PATH.as_str())); + +trait CommandDisplay { + fn display(&mut self, s: &mut String) -> &mut Self; +} + +impl CommandDisplay for Command { + fn display(&mut self, s: &mut String) -> &mut Self { + std::mem::replace(s, format_command(self)); + self + } +} + +fn format_command(cmd: &Command) -> String { + let mut s = cmd.get_program().to_str().unwrap(); + let args = cmd.get_args(); + let args = [s] + .into_iter() + .chain(args.into_iter().map(|arg| arg.to_str().unwrap())) + .collect::>() + .join(" "); + + args +} + +#[derive(clap::Parser)] +#[command(version, about, long_about = None)] +pub struct Cli { + /// SGX_MODE: + /// - SIM/SW + #[arg(long, short, default_value_t = String::from("SIM"))] + mode: String, + #[command(subcommand)] + command: Commands, +} + +#[derive(clap::Subcommand)] +pub enum Commands { + Build(BuildArg), +} + +#[derive(clap::Args)] +pub struct BuildArg { + #[arg(long, short, default_value_t = String::from("all"))] + target: String, +} + +fn main() { + let cli = Cli::parse(); + + set_mode(&cli.mode); + + match cli.command { + Commands::Build(arg) => build(&arg.target), + } + + // let args: Vec = std::env::args().collect(); + // if args.len() < 2 { + // eprintln!("Usage: xtask [options]"); + // eprintln!("Commands:"); + // eprintln!(" build Build the project"); + // eprintln!(" sign Sign the enclave"); + // eprintln!(" clean Clean build artifacts"); + // exit(1); + // } + + // match args[1].as_str() { + // "build" => build_all(), + // "sign" => sign_enclave(), + // "clean" => clean(), + // _ => { + // eprintln!("Unknown command: {}", args[1]); + // exit(1); + // } + // } +} + +pub fn set_mode(mode: &str) { + std::env::set_var("SGX_MODE", mode); +} + +pub fn build(target: &str) { + match target { + "app" => build_app(), + "enclave" => build_enclave(), + "all" => build_all(), + _ => panic!(), + } +} + +fn build_std( + path: &str, + std: &str, + flags: &str, + features: &str, +) -> Result { + let mut s = String::new(); + let output = Command::new("cargo") + .current_dir(path) + .arg(std) + .arg(flags) + .arg(features) + .stdout(std::io::stdout()) + .display(&mut s) + .output(); + println!("{s}"); + output +} + +pub fn build_all() { + // build_edl(); + build_app(); + // build_enclave(); + // link_enclave(); + // sign_enclave(); +} + +pub fn build_edl() { + println!("Building edl..."); + if !Command::new("cargo") + .arg("build") + .arg("--release") + .current_dir("edl") + .status() + .expect("Failed to build edl") + .success() + { + panic!("Failed to build edl"); + } + println!("edl built successfully."); +} + +pub fn build_app() { + println!("Building app..."); + if !Command::new("cargo") + .arg("build") + .arg("--release") + .current_dir("app") + .status() + .expect("Failed to build app") + .success() + { + panic!("Failed to build app"); + } + println!("App built successfully."); +} + +pub fn build_enclave() { + println!("Building enclave..."); + println!("Building std..."); + let output = build_std( + RUST_TARGET_PATH.as_str(), + RUST_BUILD_STD.as_str(), + RUST_TARGET_FLAGS.as_str(), + RUST_STD_FEATURES.as_str(), + ) + .unwrap(); + if !Command::new("cargo") + .arg("build") + .arg("--release") + .current_dir("enclave") + .status() + .expect("Failed to build enclave") + .success() + { + panic!("Failed to build enclave"); + } + println!("Enclave built successfully."); +} + +pub fn link_enclave() { + println!("Linking enclave..."); + let cxx = env::var("CXX").unwrap_or_else(|_| "g++".to_string()); + + let input_path = Path::new("target/release/libenclave.a"); + let output_path = Path::new("target/release/enclave.so"); + let version_script_path = Path::new("enclave/enclave.lds"); + + let status = Command::new(&cxx) + .args(&[ + input_path.to_str().unwrap(), + "-o", + output_path.to_str().unwrap(), + "-Wl,--no-undefined", + "-nostdlib", + "-nodefaultlibs", + "-nostartfiles", + "-Wl,--start-group", + "-L", + "-lenclave", + "-Wl,--end-group", + &format!( + "-Wl,--version-script={}", + version_script_path.to_str().unwrap() + ), + "-Wl,-z,relro,-z,now,-z,noexecstack", + "-Wl,-Bstatic", + "-Wl,-Bsymbolic", + "-Wl,--no-undefined", + "-Wl,-pie", + "-Wl,--export-dynamic", + "-Wl,--gc-sections", + ]) + .status() + .expect("Failed to execute g++ command"); + + if !status.success() { + eprintln!("g++ command failed with status: {}", status); + std::process::exit(1); + } + println!("Enclave linked successfully."); +} + +pub fn sign_enclave() { + let enclave_path = Path::new("target/release/enclave.so"); + let signed_path = Path::new("target/release/enclave.signed.so"); + let config_path = Path::new("enclave/config.xml"); + let key_path = Path::new("enclave/private.pem"); + + if !enclave_path.exists() { + panic!("libenclave.so not found. Please build the project first."); + } + + println!("Signing enclave..."); + if !Command::new("sgx_sign") + .arg("sign") + .arg("-key") + .arg(key_path) + .arg("-enclave") + .arg(enclave_path) + .arg("-out") + .arg(signed_path) + .arg("-config") + .arg(config_path) + .status() + .expect("Failed to sign enclave") + .success() + { + panic!("Failed to sign enclave"); + } + + println!("Enclave signed successfully."); +} + +pub fn clean() { + let paths = vec!["app/target", "enclave/target", "xtask/target", "target"]; + + for path in paths { + let dir = Path::new(path); + if dir.exists() { + println!("Cleaning {}", path); + fs::remove_dir_all(dir).expect("Failed to clean directory"); + } + } + + println!("Clean completed."); +} diff --git a/sgx_new_edl/.gitignore b/sgx_new_edl/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/sgx_new_edl/.gitignore @@ -0,0 +1 @@ +/target diff --git a/sgx_new_edl/Cargo.toml b/sgx_new_edl/Cargo.toml new file mode 100644 index 000000000..8e8d2793b --- /dev/null +++ b/sgx_new_edl/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "sgx_new_edl" +version = "0.1.0" +edition = "2021" + +[features] +default = ["enclave"] +enclave = ["sgx_tstd", "sgx_serialize/tserialize", "sgx_trts"] +app = ["sgx_serialize/userialize"] + +[dependencies] +sgx_edl_macros = { path = "sgx_edl_macros" } +sgx_types = { path = "../sgx_types" } +sgx_trts = { path = "../sgx_trts", optional = true } +sgx_tstd = { path = "../sgx_tstd", optional = true } +sgx_serialize = { path = "../sgx_serialize", default-features = false, features = [ + "derive", +] } diff --git a/sgx_new_edl/sgx_edl_macros/Cargo.toml b/sgx_new_edl/sgx_edl_macros/Cargo.toml new file mode 100644 index 000000000..6c5d806d1 --- /dev/null +++ b/sgx_new_edl/sgx_edl_macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sgx_edl_macros" +version = "0.1.0" +edition = "2021" + +[dependencies] +syn = { version = "2.0", features = ["full", "visit-mut", "visit"] } +quote = "1.0" +proc-macro2 = "1.0" +# sgx_tstd = { path = "../../sgx_tstd" } + +[lib] +proc-macro = true diff --git a/sgx_new_edl/sgx_edl_macros/src/lib.rs b/sgx_new_edl/sgx_edl_macros/src/lib.rs new file mode 100644 index 000000000..9480c23f7 --- /dev/null +++ b/sgx_new_edl/sgx_edl_macros/src/lib.rs @@ -0,0 +1,403 @@ +#![feature(proc_macro_expand)] + +use std::str::FromStr; + +use proc_macro::TokenStream; +use quote::quote; +use syn::{ + parse_macro_input, punctuated::Punctuated, token::Comma, visit::Visit, visit_mut::VisitMut, + ForeignItemFn, GenericArgument, Ident, ItemFn, Lifetime, PathArguments, Token, Type, TypePath, + Visibility, +}; + +/// name of the extern function +/// +/// Currently, to compact with existing code, +/// we use the same name with user defined function +fn extern_ecall_name(ident: &Ident) -> Ident { + Ident::new(&format!("{}", ident), ident.span()) +} + +fn extern_ocall_name(ident: &Ident) -> Ident { + Ident::new(&format!("enclave_{}", ident), ident.span()) +} + +fn raw_name(ident: &Ident) -> Ident { + Ident::new(&format!("_raw"), ident.span()) +} + +struct ReplaceLifetimes; + +impl VisitMut for ReplaceLifetimes { + fn visit_lifetime_mut(&mut self, i: &mut Lifetime) { + *i = syn::parse_quote!('a); + } +} + +struct GenericExtractor { + tys: Vec, + //lifetimes: Vec, +} + +impl Visit<'_> for GenericExtractor { + fn visit_type_path(&mut self, i: &TypePath) { + for segment in &i.path.segments { + if let PathArguments::AngleBracketed(ref args) = segment.arguments { + for arg in &args.args { + match arg { + //GenericArgument::Lifetime(lifetime) => { + // self.lifetimes.push(lifetime.clone()) + //} + GenericArgument::Type(ty) => self.tys.push(ty.clone()), + _ => {} + } + } + } + } + } + + fn visit_type_reference(&mut self, i: &syn::TypeReference) { + syn::visit::visit_type_reference(self, i); + } + + fn visit_type(&mut self, i: &Type) { + match i { + Type::Path(type_path) => self.visit_type_path(type_path), + _ => syn::visit::visit_type(self, i), + } + } +} + +#[proc_macro] +pub fn ecalls(input: TokenStream) -> TokenStream { + let s = input.to_string().split(';').collect::>().join(";,"); + let token = TokenStream::from_str(&s).unwrap(); + let parser = Punctuated::::parse_terminated; + let fns = parse_macro_input!(token with parser); + let extern_fns = gen_extern_func(&fns); + let tab = gen_ecall_table(&fns); + let fn_mods = gen_ecall_fn_mods(&fns); + quote! { + #[cfg(feature = "enclave")] + #extern_fns + #tab + #fn_mods + } + .into() +} + +fn gen_ecall_fn_mods(fns: &Punctuated) -> proc_macro2::TokenStream { + let mods = fns.iter().enumerate().map(|(idx, f)| { + let sig = &f.sig; + let args = sig.inputs.iter().collect::>(); + let args_name = args.iter().map(|arg| match arg { + syn::FnArg::Receiver(_) => unimplemented!(), + syn::FnArg::Typed(pat_type) => pat_type.pat.as_ref(), + }); + let fn_name = &sig.ident; + quote! { + #[cfg(feature = "app")] + pub mod #fn_name { + use super::*; + + pub const IDX: usize = #idx; + + pub fn ecall(eid: u64, #(#args),*) -> sgx_types::error::SgxStatus { + sgx_new_edl::app_ecall(IDX, eid, &crate::ocalls::ocall_table_enclave as * const _ as * const u8, (#(#args_name),*)) + } + } + } + }); + quote! { + #(#mods)* + } +} + +fn gen_ocall_extern_func(fns: &Punctuated) -> proc_macro2::TokenStream { + let fn_names = fns + .iter() + .map(|f| &f.sig.ident) + .map(|id| extern_ocall_name(id)); + let ret = fns.iter().map(|f| &f.sig.output); + quote! { + extern "C" { + #( + fn #fn_names(args: *const u8) #ret; + )* + } + } +} + +fn gen_extern_func(fns: &Punctuated) -> proc_macro2::TokenStream { + let fn_names = fns + .iter() + .map(|f| &f.sig.ident) + .map(|id| extern_ecall_name(id)); + let ret = fns.iter().map(|f| &f.sig.output); + quote! { + extern "C" { + #( + fn #fn_names(args: *const u8) #ret; + )* + } + } +} + +fn gen_ecall_table(fns: &Punctuated) -> proc_macro2::TokenStream { + let num = fns.len(); + let ids = fns.iter().map(|f| &f.sig.ident).map(|id| { + let extern_name = extern_ecall_name(id); + quote! { + #extern_name + } + }); + quote! { + #[cfg(feature = "enclave")] + extern crate sgx_new_edl as sgx_edl; + + #[cfg(feature = "enclave")] + #[no_mangle] + #[used] + pub static g_ecall_table: sgx_edl::EcallTable<#num> = sgx_edl::EcallTable::new([ + #(sgx_edl::EcallEntry::new(#ids)),* + ]); + //pub static g_ecall_table: &[unsafe extern "C" fn(*const u8) -> sgx_types::error::SgxStatus] = &[ + } +} + +#[proc_macro_attribute] +pub fn ecall(_attr: TokenStream, item: TokenStream) -> TokenStream { + let mut f = parse_macro_input!(item as ItemFn); + let mut raw_fn = f.clone(); + let sig = &mut f.sig; + + sig.inputs.iter_mut().for_each(|arg| { + ReplaceLifetimes.visit_fn_arg_mut(arg); + }); + + let mut ex = GenericExtractor { + tys: Vec::new(), + //lifetimes: Vec::new(), + }; + + let fn_name = &sig.ident; + let extern_name = extern_ecall_name(fn_name); + let (arg_names, arg_tys): (Vec<_>, Vec<_>) = sig + .inputs + .iter() + .map(|arg| match arg { + syn::FnArg::Receiver(_) => unimplemented!(), + syn::FnArg::Typed(pat_type) => { + ex.visit_type(&pat_type.ty); + (pat_type.pat.as_ref(), pat_type.ty.as_ref()) + } + }) + .unzip(); + + let raw_name = raw_name(fn_name); + raw_fn.vis = Visibility::Inherited; + raw_fn.sig.ident = raw_name.clone(); + + let tys = ex.tys; + + quote! { + pub mod #fn_name { + use super::*; + + struct _PhantomMarker<'a> { + _phantom: &'a () + } + + impl<'a> Default for _PhantomMarker<'a> { + fn default() -> Self { + Self { + _phantom: &() + } + } + } + + impl<'a> sgx_new_edl::Ecall<(#(#tys), *)> for _PhantomMarker<'a> { + type Args = (#(#arg_tys), *); + + fn call(&self, args: Self::Args) -> sgx_types::error::SgxStatus { + let (#(#arg_names), *) = args; + #raw_name(#(#arg_names), *) + } + } + + #[no_mangle] + pub extern "C" fn #extern_name(args: *const u8) -> sgx_types::error::SgxStatus { + sgx_new_edl::EcallWrapper::wrapper_t(&_PhantomMarker::default(), args) + } + + #raw_fn + } + } + .into() +} + +#[proc_macro_attribute] +pub fn ocall(_attr: TokenStream, item: TokenStream) -> TokenStream { + let mut f = parse_macro_input!(item as ItemFn); + let mut raw_fn = f.clone(); + let sig = &mut f.sig; + + sig.inputs.iter_mut().for_each(|arg| { + ReplaceLifetimes.visit_fn_arg_mut(arg); + }); + + let mut ex = GenericExtractor { + tys: Vec::new(), + //lifetimes: Vec::new(), + }; + + let fn_name = &sig.ident; + let extern_name = extern_ocall_name(fn_name); + let (arg_names, arg_tys): (Vec<_>, Vec<_>) = sig + .inputs + .iter() + .map(|arg| match arg { + syn::FnArg::Receiver(_) => unimplemented!(), + syn::FnArg::Typed(pat_type) => { + ex.visit_type(&pat_type.ty); + (pat_type.pat.as_ref(), pat_type.ty.as_ref()) + } + }) + .unzip(); + + let raw_name = raw_name(fn_name); + raw_fn.vis = Visibility::Inherited; + raw_fn.sig.ident = raw_name.clone(); + + let tys = ex.tys; + + quote! { + pub mod #fn_name { + use super::*; + + struct _PhantomMarker<'a> { + _phantom: &'a () + } + + impl<'a> Default for _PhantomMarker<'a> { + fn default() -> Self { + Self { + _phantom: &() + } + } + } + + impl<'a> sgx_new_edl::Ocall<(#(#tys), *)> for _PhantomMarker<'a> { + type Args = (#(#arg_tys), *); + + fn call(&self, args: Self::Args) -> sgx_types::error::SgxStatus { + let (#(#arg_names), *) = args; + #raw_name(#(#arg_names), *) + } + } + + #[no_mangle] + pub extern "C" fn #extern_name(args: *const u8) -> sgx_types::error::SgxStatus { + sgx_new_edl::OcallWrapper::wrapper(&_PhantomMarker::default(), args) + } + + #raw_fn + } + } + .into() +} + +#[proc_macro] +pub fn ocalls(input: TokenStream) -> TokenStream { + let s = input + .to_string() + .split(';') + // .filter(|s| !s.trim().is_empty()) + .collect::>() + .join(";,"); + let token = TokenStream::from_str(&s).unwrap(); + let parser = Punctuated::::parse_terminated; + let fns = parse_macro_input!(token with parser); + let extern_fns = gen_ocall_extern_func(&fns); + let tab = gen_ocall_table(&fns); + let fn_mods = gen_ocall_fn_mods(&fns); + quote! { + #[cfg(feature = "app")] + #extern_fns + #tab + #fn_mods + } + .into() +} + +fn gen_ocall_table(fns: &Punctuated) -> proc_macro2::TokenStream { + let num = fns.len(); + let ids = fns.iter().map(|f| &f.sig.ident).map(|id| { + let extern_name = extern_ocall_name(id); + quote! { + #extern_name + } + }); + + let entries = (0..num).map(|_| quote! { 0 }); + quote! { + extern crate sgx_new_edl as sgx_edl; + + #[cfg(feature = "app")] + #[no_mangle] + #[used] + pub static ocall_table_enclave: sgx_edl::OcallTable<#num> = sgx_edl::OcallTable::new([ + #(sgx_edl::OcallEntry::new(#ids)),* + ]); + + #[cfg(feature = "enclave")] + #[no_mangle] + #[used] + pub static g_dyn_entry_table: sgx_edl::DynEntryTable<#num> = sgx_edl::DynEntryTable::new([ + #(#entries),* + ]); + } +} + +fn gen_ocall_fn_mods(fns: &Punctuated) -> proc_macro2::TokenStream { + let mods = fns.iter().enumerate().filter_map(|(idx, f)| { + // Check if the function has #[no_mod] attribute + let has_no_mod = f.attrs.iter().any(|attr| attr.path().is_ident("no_impl")); + + // Skip generating module if #[no_mod] is present + if has_no_mod { + return None; + } + + let sig = &f.sig; + let args = sig.inputs.iter().collect::>(); + let args_name = args.iter().map(|arg| match arg { + syn::FnArg::Receiver(_) => unimplemented!(), + syn::FnArg::Typed(pat_type) => pat_type.pat.as_ref(), + }); + let fn_name = &sig.ident; + // let fn_name = extern_ocall_name(&sig.ident); + Some(quote! { + #[cfg(feature = "enclave")] + pub mod #fn_name { + use super::*; + + pub const IDX: usize = #idx; + + pub fn ocall(#(#args),*) -> (u32, sgx_types::error::SgxStatus) { + sgx_new_edl::enclave_ocall(IDX, (#(#args_name),*)) + } + + // #[no_mangle] + // pub extern "C" fn #fn_name(eid: u64, #(#args),*) -> sgx_types::error::SgxStatus { + // // ocall(eid, (#(#args_name),*)) + // todo!() + // } + } + }) + }); + + quote! { + #(#mods)* + } +} diff --git a/sgx_new_edl/src/arg.rs b/sgx_new_edl/src/arg.rs new file mode 100644 index 000000000..9c7df90f6 --- /dev/null +++ b/sgx_new_edl/src/arg.rs @@ -0,0 +1,247 @@ +use crate::ecall::EcallArg; +use crate::ocall::OcallArg; +use crate::ser::*; + +use std::boxed::Box; +use std::vec::Vec; + +pub trait Update { + fn update(&mut self, other: &Self); +} + +pub struct In<'a, T: Encodable + Decodable> { + inner: &'a T, +} + +impl<'a, T: Decodable + Encodable> In<'a, T> { + pub fn new(value: &'a T) -> Self { + Self { inner: value } + } + + pub fn get(self) -> &'a T { + self.inner + } +} + +impl<'a, T: Encodable + Decodable> EcallArg for In<'a, T> { + fn serialize(&self) -> Vec { + // the address is all we need + let ptr = self.inner as *const T as usize; + serialize(&ptr).unwrap() + } + + fn deserialize(data: &[u8]) -> Self { + let addr: usize = deserialize(data).unwrap(); + let inner = unsafe { &*(addr as *mut T) }; + Self { inner } + } + + fn prepare(&self) -> T { + let bytes = serialize(self.inner).unwrap(); + deserialize(&bytes).unwrap() + } + + unsafe fn _from_mut(ptr: &mut T) -> Self { + Self { + inner: &*(ptr as *mut T), + } + } + + fn update(&mut self, _: Self) {} +} + +impl<'a, Target: Encodable + Decodable> OcallArg for In<'a, Target> { + fn serialize(&self) -> Vec { + let bytes = serialize(self.inner).unwrap(); + bytes + } + + fn deserialize(data: &[u8]) -> Self { + let inner = deserialize::(data).unwrap(); + Self { + inner: Box::leak(Box::new(inner)), + } + } + + unsafe fn _clone(&mut self) -> Self { + Self { + inner: &*(self.inner as *const Target), + } + } + + unsafe fn destory(self) { + let _ = Box::from_raw(self.inner as *const Target as *mut Target); + } +} + +pub struct Out<'a, T: Decodable + Encodable + Update> { + inner: &'a mut T, +} + +impl<'a, T: Decodable + Encodable + Update> EcallArg for Out<'a, T> { + fn serialize(&self) -> Vec { + // 我们需要记录位于enclave外部的指针,后续我们会使用 + let ptr = self.inner as *const T as usize; + serialize(&ptr).unwrap() + } + + fn deserialize(data: &[u8]) -> Self { + let addr: usize = deserialize(data).unwrap(); + let inner = unsafe { &mut *(addr as *mut T) }; + Self { inner } + } + + fn prepare(&self) -> T { + let bytes = serialize(self.inner).unwrap(); + deserialize(&bytes).unwrap() + } + + unsafe fn _from_mut(ptr: &mut T) -> Self { + Self { + inner: &mut *(ptr as *mut T), + } + } + + fn update(&mut self, other: Self) { + self.inner.update(&other.inner); + } +} + +// impl<'a, T: Update + Decodable + Encodable> OcallArg for Out<'a, T> { +// fn serialize(&self) -> Vec { +// // 我们需要记录位于enclave外部的指针,后续我们会使用 +// let ptr = self.inner as *const T as usize; +// serialize(&ptr).unwrap() +// } + +// fn deserialize(data: &[u8]) -> Self { +// let addr: usize = deserialize(data).unwrap(); +// let inner = unsafe { &mut *(addr as *mut T) }; +// Self { inner } +// } + +// unsafe fn _clone(&mut self) -> Self { +// Self { +// inner: &mut *(self.inner as *mut T), +// } +// } +// } + +impl<'a, T: Update + Decodable + Encodable> Out<'a, T> { + pub fn new(value: &'a mut T) -> Self { + Self { inner: value } + } + + pub fn get(self) -> &'a T { + self.inner + } + + pub fn get_mut(mut self) -> &'a mut T { + self.inner + } +} + +impl EcallArg<(T0, T1)> for (A0, A1) +where + A0: EcallArg, + A1: EcallArg, +{ + fn serialize(&self) -> Vec { + let value = (self.0.serialize(), self.1.serialize()); + serialize(&value).unwrap() + } + + unsafe fn _from_mut(ptr: &mut (T0, T1)) -> Self { + (A0::_from_mut(&mut ptr.0), A1::_from_mut(&mut ptr.1)) + } + + fn update(&mut self, other: (A0, A1)) { + todo!() + } + + fn prepare(&self) -> (T0, T1) { + todo!() + } + + fn deserialize(data: &[u8]) -> Self { + let value = deserialize::<(Vec, Vec)>(data).unwrap(); + (A0::deserialize(&value.0), A1::deserialize(&value.1)) + } + + // unsafe fn _clone(&self) -> Self { + // (A0::_clone(&self.0), A1::_clone(&self.1)) + // } +} + +// impl OcallArg<(T0, T1)> for (A0, A1) +// where +// A0: OcallArg, +// A1: OcallArg, +// { +// fn serialize(&self) -> Vec { +// let value = (self.0.serialize(), self.1.serialize()); +// serialize(&value).unwrap() +// } + +// fn deserialize(data: &[u8]) -> Self { +// let value = deserialize::<(Vec, Vec)>(data).unwrap(); +// (A0::deserialize(&value.0), A1::deserialize(&value.1)) +// } + +// fn prepare(&self) -> (T0, T1) { +// todo!() +// } + +// unsafe fn _from_mut(target: &mut (T0, T1)) -> Self { +// todo!() +// } + +// fn update(&mut self, other: (T0, T1)) { +// todo!() +// } +// } + +// pub trait OcallArg { +// fn serialize(&self) -> Vec; +// fn deserialize(data: &[u8]) -> Self; + +// fn prepare(&self) -> Target; + +// /// Reset lifetime +// unsafe fn _from_mut(target: &mut Target) -> Self; + +// /// 将enclave内部的参数更新到外部 +// fn update(&mut self, other: Target); +// } + +// impl<'a, Target: Encodable + Decodable> OcallArg for In<'a, Target> { +// fn serialize(&self) -> Vec { +// // 这里我们只需要内存地址 +// let ptr = self.inner as *const Target as usize; +// serialize(&ptr).unwrap() +// } + +// fn deserialize(data: &[u8]) -> Self { +// let addr: usize = deserialize(data).unwrap(); +// let inner = unsafe { &*(addr as *mut Target) }; +// Self { inner } +// } + +// fn prepare(&self) -> Target { +// // 这里我们需要将内存中的数据反序列化为 Target 类型 +// let bytes = serialize(self.inner).unwrap(); +// deserialize(&bytes).unwrap() +// } + +// unsafe fn _from_mut(target: &mut Target) -> Self { +// Self { +// inner: &*(target as *mut Target), +// } +// } + +// fn update(&mut self, other: Target) { +// // 这里可以实现更新逻辑 +// // 例如,如果 Target 是一个可变引用,可以直接更新 +// // self.inner = other; // 具体实现取决于 Target 的类型 +// } +// } diff --git a/sgx_new_edl/src/ecall.rs b/sgx_new_edl/src/ecall.rs new file mode 100644 index 000000000..8be4f87e5 --- /dev/null +++ b/sgx_new_edl/src/ecall.rs @@ -0,0 +1,146 @@ +// #![cfg_attr(feature = "enclave", no_std)] +// extern crate sgx_tstd as std; + +use sgx_types::error::SgxStatus; +use sgx_types::function::sgx_ecall; + +use crate::{ocall::{OcallEntry, OcallTable}, ser::*, Update}; + +use std::vec::Vec; + +pub type ExternEcallFn = unsafe extern "C" fn(*const u8) -> sgx_types::error::SgxStatus; + +pub trait EcallArg: Sized { + fn serialize(&self) -> Vec; + fn deserialize(data: &[u8]) -> Self; + + fn prepare(&self) -> Target; + + /// Reset lifetime + unsafe fn _from_mut(target: &mut Target) -> Self; + + /// 将enclave内部的参数更新到外部 + fn update(&mut self, other: Self); +} + +impl EcallArg<()> for () { + fn serialize(&self) -> Vec { + Vec::new() + } + + fn deserialize(_: &[u8]) -> Self { + () + } + + fn prepare(&self) -> () { + () + } + + unsafe fn _from_mut(_: &mut ()) -> Self { + () + } + + fn update(&mut self, _: ()) {} +} + +#[repr(C)] +pub struct EcallEntry { + pub ecall_addr: ExternEcallFn, + pub is_priv: u8, + pub is_switchless: u8, +} + +impl EcallEntry { + pub const fn new(ecall: ExternEcallFn) -> Self { + Self { + ecall_addr: ecall, + is_priv: 0, + is_switchless: 0, + } + } +} + +#[repr(C)] +pub struct EcallTable { + pub nr_ecall: usize, + pub entries: [EcallEntry; N], +} + +impl EcallTable { + pub const fn new(tab: [EcallEntry; N]) -> Self { + Self { + nr_ecall: tab.len(), + entries: tab, + } + } +} + +pub trait Ecall { + type Args: EcallArg; + + fn call(&self, args: Self::Args) -> sgx_types::error::SgxStatus; +} + +pub trait EcallWrapper { + fn wrapper_t(&self, data: *const u8) -> sgx_types::error::SgxStatus; +} + +impl EcallWrapper for P +where + P: Ecall, + Args: EcallArg, + Target: 'static, +{ + fn wrapper_t(&self, data: *const u8) -> sgx_types::error::SgxStatus { + let bytes = unsafe { + std::slice::from_raw_parts(data, core::mem::size_of::<((usize, usize), usize)>()) + }; + // ptr: arg address, len: arg bytes len, retval: sgx status address + let ((ptr, len), retval) = deserialize::<((usize, usize), usize)>(bytes).unwrap(); + let bytes = unsafe { std::slice::from_raw_parts(ptr as *const u8, len) }; + + // deserialize the arguments + let mut raw_args = Args::deserialize(&bytes); + let retval = unsafe { &mut *(retval as *mut SgxStatus) }; + let mut arg = raw_args.prepare(); + // TODO: fence + + let in_args = unsafe { Args::_from_mut(&mut arg) }; + + let in_retval = Ecall::call(self, in_args); + + // update input arguments + raw_args.update(unsafe { Args::_from_mut(&mut arg) }); + // update sgx_status + retval.update(&in_retval); + + SgxStatus::Success + } +} + +pub fn app_ecall(id: usize, eid: u64, otab: *const u8, args: Args) -> SgxStatus +where + Args: EcallArg, +{ + let data = args.serialize(); + let status = SgxStatus::default(); + // 由于序列化后的长度不确定,因此将Vec再进行一次序列化。 + + let arg = ( + (data.as_ptr() as usize, data.len()), + &status as *const SgxStatus as usize, + ); + let mut bytes = serialize(&arg).unwrap(); + + // TODO: 序列化ocall表 + let otab_ptr = otab as *const std::os::raw::c_void; + + unsafe { + sgx_ecall( + eid, + id as i32, + otab_ptr, + bytes.as_mut_ptr() as *mut std::os::raw::c_void, + ) + } +} diff --git a/sgx_new_edl/src/lib.rs b/sgx_new_edl/src/lib.rs new file mode 100644 index 000000000..6070c377f --- /dev/null +++ b/sgx_new_edl/src/lib.rs @@ -0,0 +1,43 @@ +#![feature(allocator_api)] +#![cfg_attr(all(not(target_vendor = "teaclave"), feature = "enclave"), no_std)] + +#[cfg(not(target_vendor = "teaclave"))] +#[cfg(feature = "enclave")] +extern crate sgx_tstd as std; + +use std::{alloc::Allocator, string::String, vec::Vec}; + +mod arg; +mod ecall; +mod ocall; +mod ser; + +pub use arg::{In, Out, Update}; +pub use ecall::{app_ecall, Ecall, EcallEntry, EcallTable, EcallWrapper}; +#[cfg(feature = "enclave")] +pub use ocall::enclave_ocall; +pub use ocall::{DynEntryTable, Ocall, OcallEntry, OcallTable, OcallWrapper}; +pub use ser::*; +pub use sgx_edl_macros::{ecall, ecalls, ocall, ocalls}; +// use sgx_trts::capi::{sgx_ocalloc, sgx_ocalloc_aligned}; +pub use sgx_types::error::SgxStatus; + +impl Update for String { + fn update(&mut self, other: &Self) { + if self.capacity() < other.len() { + panic!("String capacity is not enough"); + } + self.clear(); + self.push_str(other); + } +} + +impl Update for SgxStatus { + fn update(&mut self, other: &Self) { + *self = *other; + } +} + +impl Update for () { + fn update(&mut self, _: &Self) {} +} diff --git a/sgx_new_edl/src/ocall.rs b/sgx_new_edl/src/ocall.rs new file mode 100644 index 000000000..a9d434c49 --- /dev/null +++ b/sgx_new_edl/src/ocall.rs @@ -0,0 +1,161 @@ +use crate::{ser::*, Update}; +#[cfg(feature = "enclave")] +use sgx_trts::capi::{sgx_ocall, sgx_ocalloc, sgx_ocfree}; +use sgx_types::error::SgxStatus; + +pub type ExternOcallFn = unsafe extern "C" fn(*const u8) -> sgx_types::error::SgxStatus; + +use std::vec::Vec; + +pub trait OcallArg { + fn serialize(&self) -> Vec; + fn deserialize(data: &[u8]) -> Self; + + // /// 将enclave内部的参数更新到外部 + // fn update(&mut self, other: Self); + + unsafe fn _clone(&mut self) -> Self; + + unsafe fn destory(self); +} + +impl OcallArg<()> for () { + fn serialize(&self) -> Vec { + Vec::new() + } + + fn deserialize(_: &[u8]) -> Self { + () + } + + unsafe fn _clone(&mut self) -> Self { + () + } + + unsafe fn destory(self) {} +} + +pub struct DynEntryTable { + pub nr_ocall: usize, + pub entries: [EntryTable; 1], +} + +impl DynEntryTable { + pub const fn new(entries: [u8; N]) -> Self { + Self { + nr_ocall: N, + entries: [EntryTable { entries }], + } + } +} + +#[repr(C)] +pub struct EntryTable { + pub entries: [u8; N], +} + +#[repr(C)] +pub struct OcallTable { + pub nr_ocall: usize, + pub entries: [OcallEntry; N], +} + +impl OcallTable { + pub const fn new(entries: [OcallEntry; N]) -> Self { + Self { + nr_ocall: N, + entries, + } + } + + pub fn as_slice(&self) -> &[OcallEntry] { + &self.entries + } +} + +#[repr(C)] +pub struct OcallEntry { + pub ocall_addr: ExternOcallFn, +} + +impl OcallEntry { + pub const fn new(ocall: ExternOcallFn) -> Self { + Self { ocall_addr: ocall } + } +} + +pub trait Ocall { + type Args: OcallArg; + + fn call(&self, args: Self::Args) -> SgxStatus; +} + +pub trait OcallWrapper { + fn wrapper(&self, data: *const u8) -> SgxStatus; +} + +impl OcallWrapper for P +where + P: Ocall, + Args: OcallArg, + Target: 'static, +{ + fn wrapper(&self, data: *const u8) -> SgxStatus { + let msg = unsafe { &mut *(data as *mut u8 as *mut OcallMsg) }; + let bytes = unsafe { std::slice::from_raw_parts(msg.addr as *const u8, msg.len) }; + + // deserialize the arguments + let mut raw_args = Args::deserialize(&bytes); + + let in_retval = P::call(self, raw_args); + core::mem::replace(&mut msg.retval, in_retval); + + SgxStatus::Success + } +} + +#[cfg(feature = "enclave")] +pub fn enclave_ocall(idx: usize, mut args: Args) -> (u32, SgxStatus) +where + Args: OcallArg, +{ + use core::ffi::c_void; + + let mut retval = SgxStatus::default(); + let data = args.serialize(); + let size = core::mem::size_of::() + data.len(); + // allocate in untrusted memory + let tmp = unsafe { sgx_ocalloc(size) }; + if tmp.is_null() { + unsafe { sgx_ocfree() }; + return (SgxStatus::Unexpected.into(), SgxStatus::Unexpected); + } + + // 由于序列化后的长度不确定,因此将Vec再进行一次序列化。 + let msg = unsafe { &mut *(tmp as *mut OcallMsg) }; + unsafe { + *msg = OcallMsg { + addr: tmp.add(core::mem::size_of::()) as usize, + len: data.len(), + retval: SgxStatus::default(), + }; + core::slice::from_raw_parts_mut(msg.addr as *mut u8, msg.len).copy_from_slice(&data); + } + + let status = unsafe { sgx_ocall(idx as i32, tmp as *mut c_void) }; + retval = msg.retval.clone(); + // if status == 0 { + // retval = msg.retval.clone(); + // } else { + // retval = SgxStatus::Unexpected; + // } + unsafe { sgx_ocfree() }; + (status, retval) +} + +#[repr(C)] +struct OcallMsg { + addr: usize, + len: usize, + retval: SgxStatus, +} diff --git a/sgx_new_edl/src/ser.rs b/sgx_new_edl/src/ser.rs new file mode 100644 index 000000000..ce4ecd36a --- /dev/null +++ b/sgx_new_edl/src/ser.rs @@ -0,0 +1,18 @@ +use sgx_serialize::opaque::{decode, encode}; +pub use sgx_serialize::{Decodable, Deserialize, Encodable, Serialize}; + +use std::vec::Vec; + +#[derive(Debug)] +pub struct EncodeError; + +#[derive(Debug)] +pub struct DecodeError; + +pub fn serialize(object: &T) -> Result, EncodeError> { + encode(object).ok_or(EncodeError) +} + +pub fn deserialize(bytes: &[u8]) -> Result { + decode(bytes).ok_or(DecodeError) +}