]> git.lizzy.rs Git - rust.git/commitdiff
SGX target: simplify usercall internals
authorJethro Beekman <jethro@fortanix.com>
Wed, 6 Feb 2019 16:58:45 +0000 (22:28 +0530)
committerJethro Beekman <jethro@fortanix.com>
Wed, 6 Feb 2019 17:54:55 +0000 (23:24 +0530)
This moves logic from assembly to Rust and removes the special
case for exit/panic handling, merging it with regular usercall
handling.

Also, this fixes a bug in the exit usercall introduced in a75ae00.
The bug would make regular exits look like panics with high
probability. It would also with some probability leak information
through uncleared registers.

src/libstd/lib.rs
src/libstd/sys/sgx/abi/entry.S
src/libstd/sys/sgx/abi/mod.rs
src/libstd/sys/sgx/abi/panic.rs
src/libstd/sys/sgx/abi/usercalls/mod.rs
src/libstd/sys/sgx/abi/usercalls/raw.rs
src/libstd/sys/sgx/mod.rs

index 244caf28ec7cd8075e94296f5ac3cfd6144bcf83..d1cf087c35563963a9446d31a763a46c8975832e 100644 (file)
 #[cfg(test)] extern crate std as realstd;
 
 #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-#[macro_use]
-#[allow(unused_imports)] // FIXME: without `#[macro_use]`, get error: “cannot
-                         // determine resolution for the macro `usercalls_asm`”
 extern crate fortanix_sgx_abi;
 
 // The standard macros that are not built-in to the compiler.
index 9b46c2180d9a25a3a05853b6872b85272ff03f6d..c03e3869aa3c87a09db7b761bd643ea926c0ffcf 100644 (file)
@@ -69,10 +69,6 @@ IMAGE_BASE:
     .asciz "Re-entered aborted enclave!"
 .Lreentry_panic_msg_end:
 
-.Lusercall_panic_msg:
-    .asciz "Invalid usercall#!"
-.Lusercall_panic_msg_end:
-
 .org .Lxsave_clear+512
 .Lxsave_header:
     .int 0, 0 /*  XSTATE_BV */
@@ -219,13 +215,21 @@ sgx_entry:
     orq $8,%rsp
     jmp panic_msg
 
-.Lusercall_panic:
-    lea .Lusercall_panic_msg(%rip),%rdi
-    mov $.Lusercall_panic_msg_end-.Lusercall_panic_msg,%esi
-    orq $8,%rsp
-    jmp panic_msg
-
-.macro push_callee_saved_registers
+/*  This *MUST* be called with 6 parameters, otherwise register information */
+/*  might leak! */
+.global usercall
+usercall:
+    test %rcx,%rcx            /* check `abort` function argument */
+    jnz .Lusercall_abort      /* abort is set, jump to abort code (unlikely forward conditional) */
+    jmp .Lusercall_save_state /* non-aborting usercall */
+.Lusercall_abort:
+/* set aborted bit */
+    movb $1,.Laborted(%rip)
+/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
+    testb $0xff,DEBUG(%rip)
+    jz .Lusercall_noreturn
+.Lusercall_save_state:
+/*  save callee-saved state */
     push %r15
     push %r14
     push %r13
@@ -235,33 +239,8 @@ sgx_entry:
     sub $8, %rsp
     fstcw 4(%rsp)
     stmxcsr (%rsp)
-.endm
-
-.global usercall_exit
-usercall_exit:
-/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
-    testb $0xff,DEBUG(%rip)
-    jz .Lskip_save_registers
-    push_callee_saved_registers
-    movq %rsp,%gs:tcsls_panic_last_rsp
-.Lskip_save_registers:
-/* set aborted bit */
-    movb $1,.Laborted(%rip)
-/* call usercall exit(true) */
-    /* NOP: mov %rsi,%rsi */ /*  RSI = usercall() argument: panic */
-    xor %rdx,%rdx /*  RDX cleared */
-    movq $usercall_nr_exit,%rdi /*  RDI = usercall exit */
-    jmp .Lexit
-
-/*  This *MUST* be called with 6 parameters, otherwise register information */
-/*  might leak! */
-.global usercall
-usercall:
-    test %rdi,%rdi
-    jle .Lusercall_panic
-/*  save callee-saved state */
-    push_callee_saved_registers
     movq %rsp,%gs:tcsls_last_rsp
+.Lusercall_noreturn:
 /*  clear general purpose register state */
     /*  RAX overwritten by ENCLU */
     /*  RBX set by sgx_exit */
@@ -281,7 +260,7 @@ usercall:
     jmp .Lsgx_exit
 .Lusercall_ret:
     movq $0,%gs:tcsls_last_rsp
-/*  restore callee-saved state, cf. push_callee_saved_registers */
+/*  restore callee-saved state, cf. "save" above */
     mov %r11,%rsp
     ldmxcsr (%rsp)
     fldcw 4(%rsp)
index 5ef069aa81c66641ca8904b9c70efb775a1ef067..509a1990d978b46ba7f533c649f958f268f99049 100644 (file)
@@ -12,7 +12,7 @@
 #[macro_use]
 pub mod usercalls;
 
-global_asm!(concat!(usercalls_asm!(), include_str!("entry.S")));
+global_asm!(include_str!("entry.S"));
 
 #[no_mangle]
 unsafe extern "C" fn tcs_init(secondary: bool) {
index d23fa9a9ec6f9783c4c653101d8a22b1bc49f271..b2afacc70b82e504a5925675d12d1473eff03a57 100644 (file)
@@ -1,4 +1,4 @@
-use super::usercalls::alloc::UserRef;
+use super::usercalls::{alloc::UserRef, self};
 use cmp;
 use io::{self, Write};
 use mem;
@@ -52,7 +52,5 @@ fn flush(&mut self) -> io::Result<()> {
 #[no_mangle]
 pub extern "C" fn panic_msg(msg: &str) -> ! {
     let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
-    unsafe { usercall_exit(true); }
+    usercalls::exit(true)
 }
-
-extern "C" { pub fn usercall_exit(panic: bool) -> !; }
index bae044b906b1621514f638d9252b0c83d8a42c3a..511d6e9e9273ab870cfbf9ca839438b49c9830a4 100644 (file)
@@ -120,7 +120,7 @@ pub unsafe fn launch_thread() -> IoResult<()> {
 /// Usercall `exit`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn exit(panic: bool) -> ! {
-    unsafe { super::panic::usercall_exit(panic) }
+    unsafe { raw::exit(panic) }
 }
 
 /// Usercall `wait`. See the ABI documentation for more information.
index 27f780ca224dbe3cda3cdadc4712b01be902c488..0776382d3c16bca1bdf1cdffd56a713188746194 100644 (file)
@@ -4,12 +4,13 @@
 pub use fortanix_sgx_abi::*;
 
 use ptr::NonNull;
+use num::NonZeroU64;
 
 #[repr(C)]
 struct UsercallReturn(u64, u64);
 
 extern "C" {
-    fn usercall(nr: u64, p1: u64, p2: u64, _ignore: u64, p3: u64, p4: u64) -> UsercallReturn;
+    fn usercall(nr: NonZeroU64, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64) -> UsercallReturn;
 }
 
 /// Perform the raw usercall operation as defined in the ABI calling convention.
 /// # Panics
 /// Panics if `nr` is 0.
 #[unstable(feature = "sgx_platform", issue = "56975")]
-pub unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) {
-    if nr==0 { panic!("Invalid usercall number {}",nr) }
-    let UsercallReturn(a, b) = usercall(nr,p1,p2,0,p3,p4);
+#[inline]
+pub unsafe fn do_usercall(nr: NonZeroU64, p1: u64, p2: u64, p3: u64, p4: u64, abort: bool)
+    -> (u64, u64)
+{
+    let UsercallReturn(a, b) = usercall(nr, p1, p2, abort as _, p3, p4);
     (a, b)
 }
 
@@ -39,7 +42,6 @@ trait ReturnValue {
 }
 
 macro_rules! define_usercalls {
-    // Using `$r:tt` because `$r:ty` doesn't match ! in `clobber_diverging`
     ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*) => {
         /// Usercall numbers as per the ABI.
         #[repr(u64)]
@@ -57,22 +59,6 @@ pub enum Usercalls {
     };
 }
 
-macro_rules! define_usercalls_asm {
-    ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)*; )*) => {
-        macro_rules! usercalls_asm {
-            () => {
-                concat!(
-                    ".equ usercall_nr_LAST, 0\n",
-                    $(
-                    ".equ usercall_nr_", stringify!($f), ", usercall_nr_LAST+1\n",
-                    ".equ usercall_nr_LAST, usercall_nr_", stringify!($f), "\n"
-                    ),*
-                )
-            }
-        }
-    };
-}
-
 macro_rules! define_ra {
     (< $i:ident > $t:ty) => {
         impl<$i> RegisterArgument for $t {
@@ -171,74 +157,90 @@ fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self {
     }
 }
 
+macro_rules! return_type_is_abort {
+    (!) => { true };
+    ($r:ty) => { false };
+}
+
+// In this macro: using `$r:tt` because `$r:ty` doesn't match ! in `return_type_is_abort`
 macro_rules! enclave_usercalls_internal_define_usercalls {
     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty,
-                     $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:ty) => (
+                     $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:tt) => (
         /// This is the raw function definition, see the ABI documentation for
         /// more information.
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                Usercalls::$f as Register,
+                NonZeroU64::new(Usercalls::$f as Register)
+                    .expect("Usercall number must be non-zero"),
                 RegisterArgument::into_register($n1),
                 RegisterArgument::into_register($n2),
                 RegisterArgument::into_register($n3),
                 RegisterArgument::into_register($n4),
+                return_type_is_abort!($r)
             ))
         }
     );
-    (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:ty) => (
+    (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => (
         /// This is the raw function definition, see the ABI documentation for
         /// more information.
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                Usercalls::$f as Register,
+                NonZeroU64::new(Usercalls::$f as Register)
+                    .expect("Usercall number must be non-zero"),
                 RegisterArgument::into_register($n1),
                 RegisterArgument::into_register($n2),
                 RegisterArgument::into_register($n3),
-                0
+                0,
+                return_type_is_abort!($r)
             ))
         }
     );
-    (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:ty) => (
+    (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => (
         /// This is the raw function definition, see the ABI documentation for
         /// more information.
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                Usercalls::$f as Register,
+                NonZeroU64::new(Usercalls::$f as Register)
+                    .expect("Usercall number must be non-zero"),
                 RegisterArgument::into_register($n1),
                 RegisterArgument::into_register($n2),
-                0,0
+                0,0,
+                return_type_is_abort!($r)
             ))
         }
     );
-    (def fn $f:ident($n1:ident: $t1:ty) -> $r:ty) => (
+    (def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => (
         /// This is the raw function definition, see the ABI documentation for
         /// more information.
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1) -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                Usercalls::$f as Register,
+                NonZeroU64::new(Usercalls::$f as Register)
+                    .expect("Usercall number must be non-zero"),
                 RegisterArgument::into_register($n1),
-                0,0,0
+                0,0,0,
+                return_type_is_abort!($r)
             ))
         }
     );
-    (def fn $f:ident() -> $r:ty) => (
+    (def fn $f:ident() -> $r:tt) => (
         /// This is the raw function definition, see the ABI documentation for
         /// more information.
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f() -> $r {
             ReturnValue::from_registers(stringify!($f), do_usercall(
-                Usercalls::$f as Register,
-                0,0,0,0
+                NonZeroU64::new(Usercalls::$f as Register)
+                    .expect("Usercall number must be non-zero"),
+                0,0,0,0,
+                return_type_is_abort!($r)
             ))
         }
     );
@@ -248,4 +250,3 @@ pub unsafe fn $f() -> $r {
 }
 
 invoke_with_usercalls!(define_usercalls);
-invoke_with_usercalls!(define_usercalls_asm);
index f2593c35bed14c6c79103d2716e6b0a098e9627f..4225ecbb206510d49f55c84a5dc1c876ccf0a928 100644 (file)
@@ -125,7 +125,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
 }
 
 pub unsafe fn abort_internal() -> ! {
-    abi::panic::usercall_exit(true)
+    abi::usercalls::exit(true)
 }
 
 pub fn hashmap_random_keys() -> (u64, u64) {