Initial forward-edge CFI implementation (#3693)

* Initial forward-edge CFI implementation

Give the user the option to start all basic blocks that are targets
of indirect branches with the BTI instruction introduced by the
Branch Target Identification extension to the Arm instruction set
architecture.

Copyright (c) 2022, Arm Limited.

* Refactor `from_artifacts` to avoid second `make_executable` (#1)

This involves "parsing" twice but this is parsing just the header of an
ELF file so it's not a very intensive operation and should be ok to do
twice.

* Address the code review feedback

Copyright (c) 2022, Arm Limited.

Co-authored-by: Alex Crichton <alex@alexcrichton.com>
This commit is contained in:
Anton Kirilov
2022-09-08 15:35:58 +01:00
committed by GitHub
parent caad14826c
commit d8b290898c
32 changed files with 441 additions and 105 deletions

View File

@@ -164,7 +164,7 @@ impl Component {
let static_modules = static_modules?;
let (lowerings, always_trap, transcoders, trampolines, trampoline_obj) = trampolines?;
let mut trampoline_obj = CodeMemory::new(trampoline_obj);
let code = trampoline_obj.publish()?;
let code = trampoline_obj.publish(engine.compiler().is_branch_protection_enabled())?;
let text = wasmtime_jit::subslice_range(code.text, code.mmap);
// This map is used to register all known tramplines in the

View File

@@ -462,6 +462,9 @@ impl Engine {
"sign_return_address" => Some(true),
// No effect on its own.
"sign_return_address_with_bkey" => Some(true),
// The `BTI` instruction acts as a `NOP` when unsupported, so it
// is safe to enable it.
"use_bti" => Some(true),
// fall through to the very bottom to indicate that support is
// not enabled to test whether this feature is enabled on the
// host.

View File

@@ -1,7 +1,7 @@
use crate::Engine;
use crate::{
signatures::SignatureCollection,
types::{ExportType, ExternType, ImportType},
Engine,
};
use anyhow::{bail, Context, Result};
use once_cell::sync::OnceCell;
@@ -328,18 +328,15 @@ impl Module {
///
/// This is where compilation actually happens of WebAssembly modules and
/// translation/parsing/validation of the binary input occurs. The actual
/// result here is a triple of:
/// result here is a combination of:
///
/// * The index into the second field of the "main module". The "main
/// module" in this case is the outermost module described by the `wasm`
/// input, and is here for the module linking proposal.
/// * A list of compilation artifacts for each module found within `wasm`.
/// Note that if module linking is disabled then this list will always
/// have a size of exactly 1. These pairs are returned by
/// `wasmtime_jit::finish_compile`.
/// * Type information about all the modules returned. All returned modules
/// have local type information with indices that refer to these returned
/// * The compilation artifacts for the module found within `wasm`, as
/// returned by `wasmtime_jit::finish_compile`.
/// * Type information about the module returned. All returned modules have
/// local type information with indices that refer to these returned
/// tables.
/// * A boolean value indicating whether forward-edge CFI has been applied
/// to the compiled module.
#[cfg(compiler)]
pub(crate) fn build_artifacts(
engine: &Engine,
@@ -431,8 +428,14 @@ impl Module {
// table lazy init.
translation.try_func_table_init();
let (mmap, info) =
wasmtime_jit::finish_compile(translation, obj, funcs, trampolines, tunables)?;
let (mmap, info) = wasmtime_jit::finish_compile(
translation,
obj,
funcs,
trampolines,
tunables,
engine.compiler().is_branch_protection_enabled(),
)?;
Ok((mmap, Some(info)))
}

View File

@@ -118,7 +118,7 @@ where
// Copy the results of JIT compilation into executable memory, and this will
// also take care of unwind table registration.
let mut code_memory = CodeMemory::new(obj);
let code = code_memory.publish()?;
let code = code_memory.publish(engine.compiler().is_branch_protection_enabled())?;
register_trampolines(engine.profiler(), &code.obj);