mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rollup merge of #129055 - Oneirical:fortanix-fortification, r=jieyouxu
Migrate `x86_64-fortanix-unknown-sgx-lvi` `run-make` test to rmake Part of #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.
This commit is contained in:
commit
fe87433e8a
@ -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()));
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
|
@ -1,23 +0,0 @@
|
||||
include ../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
|
96
tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
Normal file
96
tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -exuo pipefail
|
||||
|
||||
function build {
|
||||
CRATE=enclave
|
||||
|
||||
mkdir -p "${WORK_DIR}"
|
||||
pushd "${WORK_DIR}"
|
||||
rm -rf "${CRATE}"
|
||||
cp -a "${TEST_DIR}"/enclave .
|
||||
pushd $CRATE
|
||||
echo "${WORK_DIR}"
|
||||
# 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.
|
||||
env RUSTC_BOOTSTRAP=1
|
||||
cargo -v run --target "${TARGET}"
|
||||
popd
|
||||
popd
|
||||
}
|
||||
|
||||
function check {
|
||||
local func_re="$1"
|
||||
local checks="${TEST_DIR}/$2"
|
||||
local asm=""
|
||||
local objdump="${LLVM_BIN_DIR}/llvm-objdump"
|
||||
local filecheck="${LLVM_BIN_DIR}/FileCheck"
|
||||
local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave
|
||||
|
||||
asm=$(mktemp)
|
||||
func="$(${objdump} --syms --demangle "${enclave}" | \
|
||||
grep --only-matching -E "[[:blank:]]+${func_re}\$" | \
|
||||
sed -e 's/^[[:space:]]*//' )"
|
||||
${objdump} --disassemble-symbols="${func}" --demangle \
|
||||
"${enclave}" > "${asm}"
|
||||
${filecheck} --input-file "${asm}" "${checks}"
|
||||
|
||||
if [ "${func_re}" != "rust_plus_one_global_asm" ] &&
|
||||
[ "${func_re}" != "cmake_plus_one_c_global_asm" ] &&
|
||||
[ "${func_re}" != "cmake_plus_one_cxx_global_asm" ]; then
|
||||
# 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
|
||||
${filecheck} --implicit-check-not ret --input-file "${asm}" "${checks}"
|
||||
fi
|
||||
}
|
||||
|
||||
build
|
||||
|
||||
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 'std::io::stdio::_print::[[:alnum:]]+' print.without_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
|
Loading…
Reference in New Issue
Block a user