Skip to content

Commit

Permalink
Unrolled build for rust-lang#129055
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#129055 - Oneirical:fortanix-fortification, r=jieyouxu

Migrate `x86_64-fortanix-unknown-sgx-lvi` `run-make` test to rmake

Part of rust-lang#121876 and the associated [Google Summer of Code project](https://blog.rust-lang.org/2024/05/01/gsoc-2024-selected-projects.html).

The final Makefile! Every Makefile test is now claimed.

This is difficult to test due to the uncommon architecture it is specific to. I don't think it is in the CI (I didn't find it in `jobs.yml`, but if there is a way to test it, please do.

Locally, on Linux, it compiles and panics at the `llvm_filecheck` part (if I replace the `x86_64-fortanix-unknown-sgx` with `x86_64-unknown-linux-gnu`, of course), which is expected.

For this reason, the Makefile and associated script have been kept, but with a leading underscore.
  • Loading branch information
rust-timer authored Aug 23, 2024
2 parents b5723af + e276d22 commit 223dac1
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 94 deletions.
8 changes: 8 additions & 0 deletions src/tools/run-make-support/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ pub fn env_var_os(name: &str) -> OsString {
pub fn no_debug_assertions() -> bool {
std::env::var_os("NO_DEBUG_ASSERTIONS").is_some()
}

/// A wrapper around [`std::env::set_current_dir`] which includes the directory
/// path in the panic message.
#[track_caller]
pub fn set_current_dir<P: AsRef<std::path::Path>>(dir: P) {
std::env::set_current_dir(dir.as_ref())
.expect(&format!("could not set current directory to \"{}\"", dir.as_ref().display()));
}
2 changes: 1 addition & 1 deletion src/tools/run-make-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
pub use diff::{diff, Diff};

/// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers.
pub use env::{env_var, env_var_os};
pub use env::{env_var, env_var_os, set_current_dir};

/// Convenience helpers for running binaries and other commands.
pub use run::{cmd, run, run_fail, run_with_args};
Expand Down
1 change: 0 additions & 1 deletion src/tools/tidy/src/allowed_run_make_makefiles.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ run-make/macos-deployment-target/Makefile
run-make/split-debuginfo/Makefile
run-make/symbol-mangling-hashed/Makefile
run-make/translation/Makefile
run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
23 changes: 0 additions & 23 deletions tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile

This file was deleted.

96 changes: 96 additions & 0 deletions tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// ignore-tidy-linelength
// Reason: intel.com link

// This security test checks that the disassembled form of certain symbols
// is "hardened" - that means, the assembly instructions match a pattern that
// mitigate potential Load Value Injection vulnerabilities.
// 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

// On load value injection:
// https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/load-value-injection.html

//@ only-x86_64-fortanix-unknown-sgx

use run_make_support::{cmd, cwd, llvm_filecheck, llvm_objdump, regex, set_current_dir, target};

fn main() {
let main_dir = cwd();
set_current_dir("enclave");
// 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();
set_current_dir(&main_dir);
// Rust has various ways of adding code to a binary:
// - Rust code
// - Inline assembly
// - Global assembly
// - C/C++ code compiled as part of Rust crates
// For those different kinds, we do have very small code examples that should be
// mitigated in some way. Mostly we check that ret instructions should no longer be present.
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("rust_plus_one_global_asm", "rust_plus_one_global_asm.checks");

check("cc_plus_one_c", "cc_plus_one_c.checks");
check("cc_plus_one_c_asm", "cc_plus_one_c_asm.checks");
check("cc_plus_one_cxx", "cc_plus_one_cxx.checks");
check("cc_plus_one_cxx_asm", "cc_plus_one_cxx_asm.checks");
check("cc_plus_one_asm", "cc_plus_one_asm.checks");

check("cmake_plus_one_c", "cmake_plus_one_c.checks");
check("cmake_plus_one_c_asm", "cmake_plus_one_c_asm.checks");
check("cmake_plus_one_c_global_asm", "cmake_plus_one_c_global_asm.checks");
check("cmake_plus_one_cxx", "cmake_plus_one_cxx.checks");
check("cmake_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, mut 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::<Vec<&str>>().join(",");
assert!(!func.is_empty());
let dump = llvm_objdump()
.input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave")
.args(&["--demangle", &format!("--disassemble-symbols={func}")])
.run()
.stdout_utf8();
let dump = dump.as_bytes();

// Unique case, must succeed at one of two possible tests.
// This is because frame pointers are optional, and them being enabled requires
// an additional `popq` in the pattern checking file.
if func_re == "std::io::stdio::_print::[[:alnum:]]+" {
let output = llvm_filecheck().stdin(&dump).patterns(checks).run_unchecked();
if !output.status().success() {
checks = "print.without_frame_pointers.checks";
llvm_filecheck().stdin(&dump).patterns(checks).run();
}
} else {
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.
llvm_filecheck().args(&["--implicit-check-not", "ret"]).stdin(dump).patterns(checks).run();
}
}
69 changes: 0 additions & 69 deletions tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh

This file was deleted.

0 comments on commit 223dac1

Please sign in to comment.