Support page fault

This commit is contained in:
Tate, Hongliang Tian 2020-06-03 15:26:01 +00:00 committed by zongmin.gzm
parent 3939899e76
commit 655869711a
5 changed files with 205 additions and 18 deletions

@ -1,3 +1,17 @@
From ba4147e76c7cfe17f843b7b28bf535d04bc5db77 Mon Sep 17 00:00:00 2001
From: "Tate, Hongliang Tian" <tate.thl@antfin.com>
Date: Wed, 3 Jun 2020 08:11:35 +0000
Subject: [PATCH 1/3] Add support for integrity-only SGX files
---
samplecode/unit-test/enclave/src/lib.rs | 2 +
samplecode/unit-test/enclave/src/test_file.rs | 41 +++++++++
sgx_tprotected_fs/src/fs.rs | 84 +++++++++++++++++++
sgx_tstd/src/sgxfs.rs | 39 ++++++++-
sgx_tstd/src/sys/sgxfs.rs | 38 +++++++--
sgx_types/src/function.rs | 6 +-
6 files changed, 203 insertions(+), 7 deletions(-)
diff --git a/samplecode/unit-test/enclave/src/lib.rs b/samplecode/unit-test/enclave/src/lib.rs
index b9ea49be..d740753f 100644
--- a/samplecode/unit-test/enclave/src/lib.rs
@ -356,3 +370,78 @@ index 3c2db3a4..f96cd9e8 100644
}
/* intel sgx sdk 2.0 */
--
2.17.1
From 982897c432dd98c6d63691ddb238acd29db4233f Mon Sep 17 00:00:00 2001
From: "Tate, Hongliang Tian" <tate.thl@antfin.com>
Date: Wed, 3 Jun 2020 08:35:53 +0000
Subject: [PATCH 2/3] Add data structures for #PF and #GP exceptions
---
sgx_types/src/types.rs | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/sgx_types/src/types.rs b/sgx_types/src/types.rs
index 4f191364..651d088e 100644
--- a/sgx_types/src/types.rs
+++ b/sgx_types/src/types.rs
@@ -865,6 +865,8 @@ impl_enum! {
SGX_EXCEPTION_VECTOR_BP = 3, /* INT 3 instruction */
SGX_EXCEPTION_VECTOR_BR = 5, /* BOUND instruction */
SGX_EXCEPTION_VECTOR_UD = 6, /* UD2 instruction or reserved opcode */
+ SGX_EXCEPTION_VECTOR_GP = 13, /* General protection */
+ SGX_EXCEPTION_VECTOR_PF = 14, /* Page fault */
SGX_EXCEPTION_VECTOR_MF = 16, /* x87 FPU floating-point or WAIT/FWAIT instruction */
SGX_EXCEPTION_VECTOR_AC = 17, /* Any data reference in memory */
SGX_EXCEPTION_VECTOR_XM = 19, /* SSE/SSE2/SSE3 floating-point instruction */
@@ -922,11 +924,20 @@ cfg_if! {
}
}
+impl_struct! {
+ pub struct sgx_exinfo_t {
+ pub maddr: u64,
+ pub errcd: u32,
+ pub _unused: u32,
+ }
+}
+
impl_struct! {
pub struct sgx_exception_info_t {
pub cpu_context: sgx_cpu_context_t,
pub exception_vector: sgx_exception_vector_t,
pub exception_type: sgx_exception_type_t,
+ pub exinfo: sgx_exinfo_t,
}
}
--
2.17.1
From 43b32d82c09a796fd52b954dc0217ac9ce01c559 Mon Sep 17 00:00:00 2001
From: "Tate, Hongliang Tian" <tate.thl@antfin.com>
Date: Wed, 3 Jun 2020 08:37:47 +0000
Subject: [PATCH 3/3] Add a new exception type: simulated
---
sgx_types/src/types.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/sgx_types/src/types.rs b/sgx_types/src/types.rs
index 651d088e..ef43d7d6 100644
--- a/sgx_types/src/types.rs
+++ b/sgx_types/src/types.rs
@@ -879,6 +879,7 @@ impl_enum!{
pub enum sgx_exception_type_t {
SGX_EXCEPTION_HARDWARE = 3,
SGX_EXCEPTION_SOFTWARE = 6,
+ SGX_EXCEPTION_SIMULATED = 7,
}
}
--
2.17.1

@ -24,10 +24,11 @@ serde_json = { path = "../../deps/serde-json-sgx" }
sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd" }
[features]
default = ["integrity_only_opt", "sgx_file_cache"]
default = ["integrity_only_opt", "sgx_file_cache", "sgx1_exception_sim"]
syscall_timing = [] # Timing for each syscall. But it has cost from more ocall.
integrity_only_opt = [] # Clear bss only. It should be disabled if checking memory reads.
sgx_file_cache = [] # Cache SgxFile objects. Invalidation is unimplemented.
sgx1_exception_sim = [] # Simulate #PF and #GP exceptions on SGX 1
[target.'cfg(not(target_env = "sgx"))'.dependencies]
xmas-elf = { path = "../../deps/xmas-elf" }

@ -37,9 +37,7 @@ pub fn do_handle_exception(
user_context: *mut CpuContext,
) -> Result<isize> {
let info = unsafe { &mut *info };
if info.exception_type != sgx_exception_type_t::SGX_EXCEPTION_HARDWARE {
return_errno!(EINVAL, "Can only handle hardware exceptions");
}
check_exception_type(info.exception_type)?;
let user_context = unsafe { &mut *user_context };
*user_context = CpuContext::from_sgx(&info.cpu_context);
@ -72,3 +70,32 @@ pub fn do_handle_exception(
Ok(0)
}
// Notes about #PF and #GP exception simulation for SGX 1.
//
// SGX 1 cannot capture #PF and #GP exceptions inside enclaves. This leaves us
// no choice but to rely on untrusted info about #PF or #PG exceptions from
// outside the enclave. Due to the obvious security risk, the feature can be
// disabled.
//
// On the bright side, SGX 2 has native support for #PF and #GP exceptions. So
// this exception simulation and its security risk is not a problem in the long
// run.
#[cfg(not(feature = "sgx1_exception_sim"))]
fn check_exception_type(type_: sgx_exception_type_t) -> Result<()> {
if type_ != sgx_exception_type_t::SGX_EXCEPTION_HARDWARE {
return_errno!(EINVAL, "Can only handle hardware exceptions");
}
Ok(())
}
#[cfg(feature = "sgx1_exception_sim")]
fn check_exception_type(type_: sgx_exception_type_t) -> Result<()> {
if type_ != sgx_exception_type_t::SGX_EXCEPTION_HARDWARE
&& type_ != sgx_exception_type_t::SGX_EXCEPTION_SIMULATED
{
return_errno!(EINVAL, "Can only handle hardware / simulated exceptions");
}
Ok(())
}

@ -7,33 +7,52 @@ use crate::prelude::*;
pub struct FaultSignal {
num: SigNum,
code: i32,
addr: Option<u64>,
}
impl FaultSignal {
pub fn new(info: &sgx_exception_info_t) -> Self {
// FIXME: the following mapping from exception to signal is not accurate.
// TODO: the current mapping from exceptinon to signal is only a first
// order approximation. The resulting signum or siginfo may not be
// idential to Linux's behavior.
use sgx_exception_vector_t::*;
let (num, code) = match info.exception_vector {
let (num, code, addr) = match info.exception_vector {
// Divider exception
SGX_EXCEPTION_VECTOR_DE => (SIGFPE, FPE_INTDIV),
SGX_EXCEPTION_VECTOR_DE => (SIGFPE, FPE_INTDIV, None),
// Floating-point exception
SGX_EXCEPTION_VECTOR_MF |
// SIMD floating-point exception
SGX_EXCEPTION_VECTOR_XM => (SIGFPE, FPE_FLTDIV),
SGX_EXCEPTION_VECTOR_XM => (SIGFPE, FPE_FLTDIV, None),
// Invalid opcode exception
SGX_EXCEPTION_VECTOR_UD |
// Debug exception: should not occur in enclave; treat is as #UD
SGX_EXCEPTION_VECTOR_DB |
// Break point exception: should not occur in enclave; treat is as #UD
SGX_EXCEPTION_VECTOR_BP => (SIGILL, ILL_ILLOPC),
SGX_EXCEPTION_VECTOR_BP => (SIGILL, ILL_ILLOPC, None),
// Bound range exception
SGX_EXCEPTION_VECTOR_BR => (SIGSEGV, SEGV_BNDERR),
SGX_EXCEPTION_VECTOR_BR => (SIGSEGV, SEGV_BNDERR, None),
// Alignment check exception
SGX_EXCEPTION_VECTOR_AC => (SIGBUS, BUS_ADRALN),
// TODO: handle page fault and general protection exceptions
_ => panic!("illegal exception: cannot be converted to signal"),
SGX_EXCEPTION_VECTOR_AC => (SIGBUS, BUS_ADRALN, None),
// Page fault exception
SGX_EXCEPTION_VECTOR_PF => {
const PF_ERR_FLAG_PRESENT : u32 = 1u32 << 0;
let code = if info.exinfo.errcd & PF_ERR_FLAG_PRESENT != 0 {
SEGV_ACCERR
} else {
SEGV_MAPERR
};
let addr = Some(info.exinfo.maddr);
(SIGSEGV, code, addr)
},
// General protection exception
SGX_EXCEPTION_VECTOR_PF => (SIGBUS, BUS_ADRERR, None),
_ => panic!("exception cannot be converted to signal"),
};
Self { num, code }
Self { num, code, addr }
}
pub fn addr(&self) -> Option<u64> {
self.addr
}
}
@ -43,8 +62,8 @@ impl Signal for FaultSignal {
}
fn to_info(&self) -> siginfo_t {
let info = siginfo_t::new(self.num, self.code);
// TODO: set info.si_addr
let mut info = siginfo_t::new(self.num, self.code);
info.set_si_addr(self.addr.unwrap_or_default() as *const c_void);
info
}
}

@ -228,7 +228,7 @@ int div_maybe_zero(int x, int y) {
return x / y;
}
int test_catch_fault() {
int test_handle_sigfpe() {
#ifdef SGX_MODE_SIM
printf("WARNING: Skip this test case as we do not support "
"capturing hardware exception in SGX simulation mode\n");
@ -261,6 +261,56 @@ int test_catch_fault() {
#endif /* SGX_MODE_SIM */
}
// TODO: rewrite this in assembly
int read_maybe_null(int *p) {
return *p;
}
static void handle_sigsegv(int num, siginfo_t *info, void *_context) {
printf("SIGSEGV Caught\n");
assert(num == SIGSEGV);
assert(info->si_signo == SIGSEGV);
ucontext_t *ucontext = _context;
mcontext_t *mcontext = &ucontext->uc_mcontext;
// TODO: how long is the instruction?
// The faulty instruction should be `idiv %esi` (f7 fe)
mcontext->gregs[REG_RIP] += 2;
return;
}
int test_handle_sigsegv() {
#ifdef SGX_MODE_SIM
printf("WARNING: Skip this test case as we do not support "
"capturing hardware exception in SGX simulation mode\n");
return 0;
#else
// Set up a signal handler that handles divide-by-zero exception
struct sigaction new_action, old_action;
new_action.sa_sigaction = handle_sigsegv;
new_action.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &new_action, &old_action) < 0) {
THROW_ERROR("registering new signal handler failed");
}
if (old_action.sa_handler != SIG_DFL) {
THROW_ERROR("unexpected old sig handler");
}
int *addr = NULL;
volatile int val = read_maybe_null(addr);
printf("Signal handler successfully jumped over a null-dereferencing instruction\n");
if (sigaction(SIGSEGV, &old_action, NULL) < 0) {
THROW_ERROR("restoring old signal handler failed");
}
return 0;
#endif /* SGX_MODE_SIM */
}
// ============================================================================
// Test handle signal on alternate signal stack
// ============================================================================
@ -364,7 +414,8 @@ static test_case_t test_cases[] = {
TEST_CASE(test_raise),
TEST_CASE(test_abort),
TEST_CASE(test_kill),
TEST_CASE(test_catch_fault),
TEST_CASE(test_handle_sigfpe),
TEST_CASE(test_handle_sigsegv),
TEST_CASE(test_sigaltstack),
TEST_CASE(test_sigchld),
};