From 1f9cc33f1a8249c798ccd235c3213782cdca5a10 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 13 Aug 2024 11:33:01 -0400 Subject: [PATCH] rewrite x86_64-fortanix-unknown-sgx-lvi to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../{Makefile => _Makefile} | 3 + .../{script.sh => _script.sh} | 4 + .../x86_64-fortanix-unknown-sgx-lvi/rmake.rs | 92 +++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) rename tests/run-make/x86_64-fortanix-unknown-sgx-lvi/{Makefile => _Makefile} (76%) rename tests/run-make/x86_64-fortanix-unknown-sgx-lvi/{script.sh => _script.sh} (94%) create mode 100644 tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 14f0a9cd23d21..aa1f450e0c0de 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,4 +23,3 @@ run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile run-make/sysroot-crates-are-unstable/Makefile run-make/translation/Makefile -run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/_Makefile similarity index 76% rename from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile rename to tests/run-make/x86_64-fortanix-unknown-sgx-lvi/_Makefile index 3c88ec34f431e..49c87b6e2d987 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/_Makefile @@ -1,3 +1,6 @@ +# FIXME(Oneirical): Disabled for now. Remove this if the rmake.rs replacement +# is shown to work, or restore it if the rmake.rs replacement does not work. + include ../tools.mk #only-x86_64-fortanix-unknown-sgx diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/_script.sh similarity index 94% rename from tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh rename to tests/run-make/x86_64-fortanix-unknown-sgx-lvi/_script.sh index a7c4ae13ecb38..3315f7d6782c8 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/_script.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# FIXME(Oneirical): Disabled for now. Remove this if the rmake.rs replacement +# is shown to work, or restore it if the rmake.rs replacement does not work. + set -exuo pipefail function build { diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs new file mode 100644 index 0000000000000..ad87ee1dccddd --- /dev/null +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs @@ -0,0 +1,92 @@ +// This security test checks that the disassembled form of certain symbols +// is "hardened" - that means, the assembly instructions match a pattern that shows +// lack of vulnerability to a Load Value Injection attack. +// To do so, a test crate is compiled, and certain symbols are found, disassembled +// and checked one by one. +// See https://github.com/rust-lang/rust/pull/77008 + +//@ only-x86_64-fortanix-unknown-sgx + +use run_make_support::{cmd, cwd, llvm_filecheck, llvm_objdump, regex, target}; + +fn main() { + let main_dir = cwd(); + std::env::set_current_dir("enclave").unwrap(); + // HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. + // These come from the top-level Rust workspace, that this crate is not a + // member of, but Cargo tries to load the workspace `Cargo.toml` anyway. + cmd("cargo") + .env("RUSTC_BOOTSTRAP", "1") + .arg("-v") + .arg("run") + .arg("--target") + .arg(target()) + .run(); + std::env::set_current_dir(&main_dir).unwrap(); + check("unw_getcontext", "unw_getcontext.checks"); + check("__libunwind_Registers_x86_64_jumpto", "jumpto.checks"); + + check("std::io::stdio::_print::[[:alnum:]]+", "print.with_frame_pointers.checks"); + + check("st_plus_one_global_asm", "rust_plus_one_global_asm.checks"); + + check("_plus_one_c", "cc_plus_one_c.checks"); + check("_plus_one_c_asm", "cc_plus_one_c_asm.checks"); + check("_plus_one_cxx", "cc_plus_one_cxx.checks"); + check("_plus_one_cxx_asm", "cc_plus_one_cxx_asm.checks"); + check("_plus_one_asm", "cc_plus_one_asm.checks"); + + check("ake_plus_one_c", "cmake_plus_one_c.checks"); + check("ake_plus_one_c_asm", "cmake_plus_one_c_asm.checks"); + check("ake_plus_one_c_global_asm", "cmake_plus_one_c_global_asm.checks"); + check("ake_plus_one_cxx", "cmake_plus_one_cxx.checks"); + check("ake_plus_one_cxx_asm", "cmake_plus_one_cxx_asm.checks"); + check("cmake_plus_one_cxx_global_asm", "cmake_plus_one_cxx_global_asm.checks"); + check("cmake_plus_one_asm", "cmake_plus_one_asm.checks"); +} + +fn check(func_re: &str, checks: &str) { + let dump = llvm_objdump() + .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") + .args(&["--syms", "--demangle"]) + .run() + .stdout_utf8(); + let re = regex::Regex::new(&format!("[[:blank:]]+{func_re}")).unwrap(); + let func = re.find_iter(&dump).map(|m| m.as_str().trim()).collect::>().join(","); + let dump = llvm_objdump() + .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") + .args(&["--syms", &format!("--disassemble-symbols={func}")]) + .run() + .stdout_utf8(); + let dump = dump.as_bytes(); + + // Unique case, must succeed at one of two possible tests. + if func_re == "std::io::stdio::_print::[[:alnum:]]+" { + let output = llvm_filecheck().stdin(&dump).patterns(checks).run_unchecked(); + if !output.status().success() { + llvm_filecheck().stdin(&dump).patterns("print.without_frame_pointers.checks").run(); + llvm_filecheck() + .args(&["--implicit-check-not", "ret"]) + .stdin(dump) + .patterns("print.without_frame_pointers.checks") + .run(); + } else { + llvm_filecheck() + .args(&["--implicit-check-not", "ret"]) + .stdin(dump) + .patterns(checks) + .run(); + } + return; + } + llvm_filecheck().stdin(&dump).patterns(checks).run(); + if !["rust_plus_one_global_asm", "cmake_plus_one_c_global_asm", "cmake_plus_one_cxx_global_asm"] + .contains(&func_re) + { + // The assembler cannot avoid explicit `ret` instructions. Sequences + // of `shlq $0x0, (%rsp); lfence; retq` are used instead. + // https://www.intel.com/content/www/us/en/developer/articles/technical/ + // software-security-guidance/technical-documentation/load-value-injection.html + llvm_filecheck().args(&["--implicit-check-not", "ret"]).stdin(dump).patterns(checks).run(); + } +}