Skip to content

Commit

Permalink
Auto merge of #77008 - fortanix:raoul/lvi-tests, r=Mark-Simulacrum
Browse files Browse the repository at this point in the history
LVI hardening tests

Mitigating the speculative execution LVI attack against SGX enclaves requires compiler changes (i.e., adding lfences). This pull requests adds various tests to check if this happens correctly.
  • Loading branch information
bors committed Sep 28, 2020
2 parents db7ee7c + 159d11f commit 6369a98
Show file tree
Hide file tree
Showing 32 changed files with 519 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,14 @@ impl Step for TestHelpers {
if builder.config.dry_run {
return;
}
let target = self.target;
// The x86_64-fortanix-unknown-sgx target doesn't have a working C
// toolchain. However, some x86_64 ELF objects can be linked
// without issues. Use this hack to compile the test helpers.
let target = if self.target == "x86_64-fortanix-unknown-sgx" {
TargetSelection::from_user("x86_64-unknown-linux-gnu")
} else {
self.target
};
let dst = builder.test_helpers_out(target);
let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c");
if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
Expand All @@ -654,7 +661,6 @@ impl Step for TestHelpers {
}
cfg.compiler(builder.cc(target));
}

cfg.cargo_metadata(false)
.out_dir(&dst)
.target(&target.triple)
Expand Down
17 changes: 17 additions & 0 deletions src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Test LVI load hardening on SGX enclave code

// assembly-output: emit-asm
// compile-flags: --crate-type staticlib
// only-x86_64-fortanix-unknown-sgx

#[no_mangle]
pub extern fn plus_one(r: &mut u64) {
*r = *r + 1;
}

// CHECK: plus_one
// CHECK: lfence
// CHECK-NEXT: addq
// CHECK: popq [[REGISTER:%[a-z]+]]
// CHECK-NEXT: lfence
// CHECK-NEXT: jmpq *[[REGISTER]]
12 changes: 12 additions & 0 deletions src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Test LVI ret hardening on generic rust code

// assembly-output: emit-asm
// compile-flags: --crate-type staticlib
// only-x86_64-fortanix-unknown-sgx

#[no_mangle]
pub extern fn myret() {}
// CHECK: myret:
// CHECK: popq [[REGISTER:%[a-z]+]]
// CHECK-NEXT: lfence
// CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Test LVI load hardening on SGX inline assembly code

// assembly-output: emit-asm
// compile-flags: --crate-type staticlib
// only-x86_64-fortanix-unknown-sgx

#![feature(asm)]

#[no_mangle]
pub extern fn get(ptr: *const u64) -> u64 {
let value : u64;
unsafe {
asm!(".start_inline_asm:",
"mov {}, [{}]",
".end_inline_asm:",
out(reg) value,
in(reg) ptr);
}
value
}

// CHECK: get
// CHECK: .start_inline_asm
// CHECK-NEXT: movq
// CHECK-NEXT: lfence
// CHECK-NEXT: .end_inline_asm

#[no_mangle]
pub extern fn myret() {
unsafe {
asm!(".start_myret_inline_asm:
ret
.end_myret_inline_asm:");
}
}

// CHECK: myret
// CHECK: .start_myret_inline_asm
// CHECK-NEXT: shlq $0, (%rsp)
// CHECK-NEXT: lfence
// CHECK-NEXT: retq
23 changes: 23 additions & 0 deletions src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-include ../../run-make-fulldeps/tools.mk

#only-x86_64-fortanix-unknown-sgx

# For cargo setting
export RUSTC := $(RUSTC_ORIGINAL)
export LD_LIBRARY_PATH := $(HOST_RPATH_DIR)
# We need to be outside of 'src' dir in order to run cargo
export WORK_DIR := $(TMPDIR)
export TEST_DIR := $(shell pwd)

## clean up unused env variables which might cause harm.
unexport RUSTC_LINKER
unexport RUSTC_BOOTSTRAP
unexport RUST_BUILD_STAGE
unexport RUST_TEST_THREADS
unexport RUST_TEST_TMPDIR
unexport AR
unexport CC
unexport CXX

all:
bash script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CHECK: cc_plus_one_asm
CHECK-NEXT: movl
CHECK-NEXT: lfence
CHECK-NEXT: inc
CHECK-NEXT: notq (%rsp)
CHECK-NEXT: notq (%rsp)
CHECK-NEXT: lfence
CHECK-NEXT: retq
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CHECK: cc_plus_one_c
CHECK: lfence
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CHECK: cc_plus_one_c_asm
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK-NEXT: incl
CHECK-NEXT: jmp
CHECK-NEXT: shlq $0, (%rsp)
CHECK-NEXT: lfence
CHECK-NEXT: retq
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CHECK: cc_plus_one_cxx
CHECK: lfence
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CHECK: cc_plus_one_cxx_asm
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK: movl
CHECK: lfence
CHECK: lfence
CHECK-NEXT: incl
CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} <cc_plus_one_cxx_asm+0x{{[[:xdigit:]]+}}>
CHECK-NEXT: shlq $0, (%rsp)
CHECK-NEXT: lfence
CHECK-NEXT: retq
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CHECK: cmake_plus_one_asm
CHECK-NEXT: movl
CHECK-NEXT: lfence
CHECK-NEXT: incl
CHECK-NEXT: shlq $0, (%rsp)
CHECK-NEXT: lfence
CHECK-NEXT: retq
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CHECK: cmake_plus_one_c
CHECK: lfence
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CHECK: cmake_plus_one_c_asm
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK: movl
CHECK: lfence
CHECK-NEXT: incl
CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} <cmake_plus_one_c_asm+0x{{[[:xdigit:]]+}}>
CHECK-NEXT: shlq $0, (%rsp)
CHECK-NEXT: lfence
CHECK-NEXT: retq
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CHECK: cmake_plus_one_c_global_asm
CHECK: lfence
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CHECK: cmake_plus_one_cxx
CHECK: lfence
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CHECK: cmake_plus_one_cxx_asm
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK: lfence
CHECK: movl
CHECK: lfence
CHECK-NEXT: incl
CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} <cmake_plus_one_cxx_asm+0x{{[[:xdigit:]]+}}>
CHECK-NEXT: shlq $0, (%rsp)
CHECK-NEXT: lfence
CHECK-NEXT: retq
CHECK: popq
CHECK-NEXT: popq [[REGISTER:%[a-z]+]]
CHECK-NEXT: lfence
CHECK-NEXT: jmpq *[[REGISTER]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CHECK: cmake_plus_one_cxx_global_asm
CHECK: lfence
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "enclave"
version = "0.1.0"
authors = ["Raoul Strackx <raoul.strackx@fortanix.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[build-dependencies]
cc = "1.0"
cmake = "0.1"
30 changes: 30 additions & 0 deletions src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
fn main() {
cc::Build::new()
.file("foo.c")
.compile("foo_c");

cc::Build::new()
.file("foo_asm.s")
.compile("foo_asm");

cc::Build::new()
.cpp(true)
.cpp_set_stdlib(None)
.file("foo_cxx.cpp")
.compile("foo_cxx");

// When the cmake crate detects the clang compiler, it passes the
// "--target" argument to the linker which subsequently fails. The
// `CMAKE_C_COMPILER_FORCED` option makes sure that `cmake` does not
// tries to test the compiler. From version 3.6 the option
// `CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY` can be used
// https://cmake.org/cmake/help/v3.5/module/CMakeForceCompiler.html
let dst = cmake::Config::new("libcmake_foo")
.build_target("cmake_foo")
.define("CMAKE_C_COMPILER_FORCED", "1")
.define("CMAKE_CXX_COMPILER_FORCED", "1")
.define("CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY", "1")
.build();
println!("cargo:rustc-link-search=native={}/build/", dst.display());
println!("cargo:rustc-link-lib=static=cmake_foo");
}
18 changes: 18 additions & 0 deletions src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
int cc_plus_one_c(int *arg) {
return *arg + 1;
}

int cc_plus_one_c_asm(int *arg) {
int value = 0;

asm volatile ( " movl (%1), %0\n"
" inc %0\n"
" jmp 1f\n"
" retq\n" // never executed, but a shortcut to determine how
// the assembler deals with `ret` instructions
"1:\n"
: "=r"(value)
: "r"(arg) );

return value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.text
.global cc_plus_one_asm
.type cc_plus_one_asm, @function
cc_plus_one_asm:
movl (%rdi), %eax
inc %eax
retq
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
extern "C" int cc_plus_one_cxx(int *arg);
extern "C" int cc_plus_one_cxx_asm(int *arg);

int cc_plus_one_cxx(int *arg) {
return *arg + 1;
}

int cc_plus_one_cxx_asm(int *arg) {
int value = 0;

asm volatile ( " movl (%1), %0\n"
" inc %0\n"
" jmp 1f\n"
" retq\n" // never executed, but a shortcut to determine how
// the assembler deals with `ret` instructions
"1:\n"
: "=r"(value)
: "r"(arg) );

return value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
enable_language(C CXX ASM)

set(C_SOURCES
src/foo.c
)

set_source_files_properties(${C_SOURCES}
PROPERTIES
LANGUAGE C)

set(CXX_SOURCES
src/foo_cxx.cpp
)

set_source_files_properties(${CXX_SOURCES}
PROPERTIES
LANGUAGE CXX)

set(ASM_SOURCES
src/foo_asm.s
)

set_source_files_properties(${ASM_SOURCES}
PROPERTIES
LANGUAGE ASM)

set(SOURCES
${C_SOURCES}
${CXX_SOURCES}
${ASM_SOURCES})

add_library(cmake_foo STATIC
${SOURCES})
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
int cmake_plus_one_c(int *arg) {
return *arg + 1;
}

int cmake_plus_one_c_asm(int *arg) {
int value = 0;

asm volatile ( " movl (%1), %0\n"
" inc %0\n"
" jmp 1f\n"
" retq\n" // never executed, but a shortcut to determine how
// the assembler deals with `ret` instructions
"1:\n"
: "=r"(value)
: "r"(arg) );

return value;
}

asm(".text\n"
" .global cmake_plus_one_c_global_asm\n"
" .type cmake_plus_one_c_global_asm, @function\n"
"cmake_plus_one_c_global_asm:\n"
" movl (%rdi), %eax\n"
" inc %eax\n"
" retq\n" );
Loading

0 comments on commit 6369a98

Please sign in to comment.