Skip to content

Commit

Permalink
Auto merge of rust-lang#58235 - jethrogb:jb/sgx-usercall-internals, r…
Browse files Browse the repository at this point in the history
…=alexcrichton

SGX target: simplify usercall internals

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.

cc @VardhanThigle

r? @alexcrichton
  • Loading branch information
bors committed Feb 13, 2019
2 parents 827a141 + 0d2ab0b commit ccd23b9
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 84 deletions.
3 changes: 0 additions & 3 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,6 @@ extern crate backtrace_sys;
#[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.
Expand Down
55 changes: 17 additions & 38 deletions src/libstd/sys/sgx/abi/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand All @@ -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 */
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/sys/sgx/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub mod tls;
#[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) {
Expand Down
6 changes: 2 additions & 4 deletions src/libstd/sys/sgx/abi/panic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::usercalls::alloc::UserRef;
use super::usercalls::{alloc::UserRef, self};
use cmp;
use io::{self, Write};
use mem;
Expand Down Expand Up @@ -52,7 +52,5 @@ impl Write for SgxPanicOutput {
#[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) -> !; }
2 changes: 1 addition & 1 deletion src/libstd/sys/sgx/abi/usercalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
73 changes: 37 additions & 36 deletions src/libstd/sys/sgx/abi/usercalls/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/// Performs the raw usercall operation as defined in the ABI calling convention.
Expand All @@ -23,9 +24,11 @@ extern "C" {
///
/// 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)
}

Expand All @@ -41,7 +44,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)]
Expand All @@ -59,22 +61,6 @@ macro_rules! define_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 {
Expand Down Expand Up @@ -173,74 +159,90 @@ impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
}
}

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)
))
}
);
Expand All @@ -250,4 +252,3 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
}

invoke_with_usercalls!(define_usercalls);
invoke_with_usercalls!(define_usercalls_asm);
2 changes: 1 addition & 1 deletion src/libstd/sys/sgx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit ccd23b9

Please sign in to comment.