Rollup merge of #57971 - jethrogb:jb/sgx-panic, r=alexcrichton

SGX target: improve panic & exit handling

Implement this part of the spec:

> The enclave must not rely on userspace to terminate other threads still running. Similarly, the enclave must not trust that it will no longer be entered by userspace, and it must safeguard against that in the entrypoints.

Also use `UserRef` to access panic buffer

r? @alexcrichton

cc @VardhanThigle
This commit is contained in:
Mazdak Farrokhzad 2019-01-31 02:10:45 +01:00 committed by GitHub
commit fb7721a594
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 22 deletions

View File

@ -66,7 +66,7 @@ IMAGE_BASE:
globvar EH_FRM_HDR_SIZE 8 globvar EH_FRM_HDR_SIZE 8
.Lreentry_panic_msg: .Lreentry_panic_msg:
.asciz "Re-entered panicked enclave!" .asciz "Re-entered aborted enclave!"
.Lreentry_panic_msg_end: .Lreentry_panic_msg_end:
.Lusercall_panic_msg: .Lusercall_panic_msg:
@ -80,7 +80,7 @@ IMAGE_BASE:
.org .+48 /* reserved bits */ .org .+48 /* reserved bits */
.data .data
.Lpanicked: .Laborted:
.byte 0 .byte 0
/* TCS local storage section */ /* TCS local storage section */
@ -134,6 +134,9 @@ sgx_entry:
jz .Lskip_debug_init jz .Lskip_debug_init
mov %r10,%gs:tcsls_debug_panic_buf_ptr mov %r10,%gs:tcsls_debug_panic_buf_ptr
.Lskip_debug_init: .Lskip_debug_init:
/* check for abort */
bt $0,.Laborted(%rip)
jc .Lreentry_panic
/* check if returning from usercall */ /* check if returning from usercall */
mov %gs:tcsls_last_rsp,%r11 mov %gs:tcsls_last_rsp,%r11
test %r11,%r11 test %r11,%r11
@ -164,9 +167,6 @@ sgx_entry:
mov %r14,%r8 mov %r14,%r8
mov %r15,%r9 mov %r15,%r9
.Lskip_init: .Lskip_init:
/* check for panic */
bt $0,.Lpanicked(%rip)
jc .Lreentry_panic
/* call into main entry point */ /* call into main entry point */
load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */ load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */ call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
@ -237,18 +237,18 @@ sgx_entry:
stmxcsr (%rsp) stmxcsr (%rsp)
.endm .endm
.global panic_exit .global usercall_exit
panic_exit: usercall_exit:
/* save registers in DEBUG mode, so that debugger can reconstruct the stack */ /* save registers in DEBUG mode, so that debugger can reconstruct the stack */
testb $0xff,DEBUG(%rip) testb $0xff,DEBUG(%rip)
jz .Lskip_save_registers jz .Lskip_save_registers
push_callee_saved_registers push_callee_saved_registers
movq %rsp,%gs:tcsls_panic_last_rsp movq %rsp,%gs:tcsls_panic_last_rsp
.Lskip_save_registers: .Lskip_save_registers:
/* set panicked bit */ /* set aborted bit */
movb $1,.Lpanicked(%rip) movb $1,.Laborted(%rip)
/* call usercall exit(true) */ /* call usercall exit(true) */
mov $1,%esi /* RSI = usercall() argument: panic = true */ /* NOP: mov %rsi,%rsi */ /* RSI = usercall() argument: panic */
xor %rdx,%rdx /* RDX cleared */ xor %rdx,%rdx /* RDX cleared */
movq $usercall_nr_exit,%rdi /* RDI = usercall exit */ movq $usercall_nr_exit,%rdi /* RDI = usercall exit */
jmp .Lexit jmp .Lexit

View File

@ -1,12 +1,18 @@
use super::usercalls::alloc::UserRef;
use cmp;
use io::{self, Write}; use io::{self, Write};
use slice::from_raw_parts_mut; use mem;
extern "C" { extern "C" {
fn take_debug_panic_buf_ptr() -> *mut u8; fn take_debug_panic_buf_ptr() -> *mut u8;
static DEBUG: u8; static DEBUG: u8;
} }
pub(crate) struct SgxPanicOutput(Option<&'static mut [u8]>); pub(crate) struct SgxPanicOutput(Option<&'static mut UserRef<[u8]>>);
fn empty_user_slice() -> &'static mut UserRef<[u8]> {
unsafe { UserRef::from_raw_parts_mut(1 as *mut u8, 0) }
}
impl SgxPanicOutput { impl SgxPanicOutput {
pub(crate) fn new() -> Option<Self> { pub(crate) fn new() -> Option<Self> {
@ -17,32 +23,36 @@ impl SgxPanicOutput {
} }
} }
fn init(&mut self) -> &mut &'static mut [u8] { fn init(&mut self) -> &mut &'static mut UserRef<[u8]> {
self.0.get_or_insert_with(|| unsafe { self.0.get_or_insert_with(|| unsafe {
let ptr = take_debug_panic_buf_ptr(); let ptr = take_debug_panic_buf_ptr();
if ptr.is_null() { if ptr.is_null() {
&mut [] empty_user_slice()
} else { } else {
from_raw_parts_mut(ptr, 1024) UserRef::from_raw_parts_mut(ptr, 1024)
} }
}) })
} }
} }
impl Write for SgxPanicOutput { impl Write for SgxPanicOutput {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, src: &[u8]) -> io::Result<usize> {
self.init().write(buf) let dst = mem::replace(self.init(), empty_user_slice());
let written = cmp::min(src.len(), dst.len());
dst[..written].copy_from_enclave(&src[..written]);
self.0 = Some(&mut dst[written..]);
Ok(written)
} }
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
self.init().flush() Ok(())
} }
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn panic_msg(msg: &str) -> ! { pub extern "C" fn panic_msg(msg: &str) -> ! {
let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes())); let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
unsafe { panic_exit(); } unsafe { usercall_exit(true); }
} }
extern "C" { pub fn panic_exit() -> !; } extern "C" { pub fn usercall_exit(panic: bool) -> !; }

View File

@ -119,7 +119,7 @@ pub unsafe fn launch_thread() -> IoResult<()> {
/// Usercall `exit`. See the ABI documentation for more information. /// Usercall `exit`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")] #[unstable(feature = "sgx_platform", issue = "56975")]
pub fn exit(panic: bool) -> ! { pub fn exit(panic: bool) -> ! {
unsafe { raw::exit(panic) } unsafe { super::panic::usercall_exit(panic) }
} }
/// Usercall `wait`. See the ABI documentation for more information. /// Usercall `wait`. See the ABI documentation for more information.

View File

@ -125,7 +125,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
} }
pub unsafe fn abort_internal() -> ! { pub unsafe fn abort_internal() -> ! {
abi::panic::panic_exit() abi::panic::usercall_exit(true)
} }
pub fn hashmap_random_keys() -> (u64, u64) { pub fn hashmap_random_keys() -> (u64, u64) {