Add cross-language LLVM CFI support to the Rust compiler
This commit adds cross-language LLVM Control Flow Integrity (CFI) support to the Rust compiler by adding the `-Zsanitizer-cfi-normalize-integers` option to be used with Clang `-fsanitize-cfi-icall-normalize-integers` for normalizing integer types (see https://reviews.llvm.org/D139395). It provides forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same virtual address space). For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, see design document in the tracking issue #89653. Cross-language LLVM CFI can be enabled with -Zsanitizer=cfi and -Zsanitizer-cfi-normalize-integers, and requires proper (i.e., non-rustc) LTO (i.e., -Clinker-plugin-lto).
This commit is contained in:
parent
fec9adcdbc
commit
004aa15b47
70 changed files with 1384 additions and 387 deletions
|
@ -35,7 +35,15 @@ session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible
|
|||
|
||||
session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
|
||||
|
||||
session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto`
|
||||
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
|
||||
|
||||
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
|
||||
|
||||
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
|
||||
|
||||
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
|
||||
|
||||
session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
|
||||
|
||||
session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
|
||||
|
||||
|
|
|
@ -1036,6 +1036,14 @@ fn default_configuration(sess: &Session) -> CrateConfig {
|
|||
ret.insert((sym::sanitize, Some(symbol)));
|
||||
}
|
||||
|
||||
if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
ret.insert((sym::sanitizer_cfi_generalize_pointers, None));
|
||||
}
|
||||
|
||||
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
ret.insert((sym::sanitizer_cfi_normalize_integers, None));
|
||||
}
|
||||
|
||||
if sess.opts.debug_assertions {
|
||||
ret.insert((sym::debug_assertions, None));
|
||||
}
|
||||
|
|
|
@ -111,8 +111,24 @@ pub struct CannotMixAndMatchSanitizers {
|
|||
pub struct CannotEnableCrtStaticLinux;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_enabled)]
|
||||
pub struct SanitizerCfiEnabled;
|
||||
#[diag(session_sanitizer_cfi_requires_lto)]
|
||||
pub struct SanitizerCfiRequiresLto;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_canonical_jump_tables_requires_cfi)]
|
||||
pub struct SanitizerCfiCanonicalJumpTablesRequiresCfi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_generalize_pointers_requires_cfi)]
|
||||
pub struct SanitizerCfiGeneralizePointersRequiresCfi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
|
||||
pub struct SanitizerCfiNormalizeIntegersRequiresCfi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_split_lto_unit_requires_lto)]
|
||||
pub struct SplitLtoUnitRequiresLto;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_unstable_virtual_function_elimination)]
|
||||
|
|
|
@ -1659,6 +1659,12 @@ options! {
|
|||
"immediately print bugs registered with `delay_span_bug` (default: no)"),
|
||||
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
"use a sanitizer"),
|
||||
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
|
||||
"enable canonical jump tables (default: yes)"),
|
||||
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable generalizing pointer types (default: no)"),
|
||||
sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable normalizing integer types (default: no)"),
|
||||
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
|
||||
"enable origins tracking in MemorySanitizer"),
|
||||
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
|
@ -1704,6 +1710,8 @@ options! {
|
|||
file which is ignored by the linker
|
||||
`single`: sections which do not require relocation are written into object file but ignored
|
||||
by the linker"),
|
||||
split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"enable LTO unit splitting (default: no)"),
|
||||
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
|
||||
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
|
||||
|
|
|
@ -766,10 +766,30 @@ impl Session {
|
|||
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(false)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_canonical_jump_tables_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(true)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_generalize_pointers_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_generalize_pointers == Some(true)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_normalize_integers_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
|
||||
}
|
||||
|
||||
pub fn is_split_lto_unit_enabled(&self) -> bool {
|
||||
self.opts.unstable_opts.split_lto_unit == Some(true)
|
||||
}
|
||||
|
||||
/// Check whether this compile session and crate type use static crt.
|
||||
pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
|
||||
if !self.target.crt_static_respected {
|
||||
|
@ -1581,17 +1601,16 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
sess.emit_err(errors::CannotEnableCrtStaticLinux);
|
||||
}
|
||||
|
||||
// LLVM CFI and VFE both require LTO.
|
||||
if sess.lto() != config::Lto::Fat {
|
||||
if sess.is_sanitizer_cfi_enabled() {
|
||||
sess.emit_err(errors::SanitizerCfiEnabled);
|
||||
}
|
||||
if sess.opts.unstable_opts.virtual_function_elimination {
|
||||
sess.emit_err(errors::UnstableVirtualFunctionElimination);
|
||||
}
|
||||
// LLVM CFI requires LTO.
|
||||
if sess.is_sanitizer_cfi_enabled()
|
||||
&& !(sess.lto() == config::Lto::Fat
|
||||
|| sess.lto() == config::Lto::Thin
|
||||
|| sess.opts.cg.linker_plugin_lto.enabled())
|
||||
{
|
||||
sess.emit_err(errors::SanitizerCfiRequiresLto);
|
||||
}
|
||||
|
||||
// LLVM CFI and KCFI are mutually exclusive
|
||||
// LLVM CFI is incompatible with LLVM KCFI.
|
||||
if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
|
||||
sess.emit_err(errors::CannotMixAndMatchSanitizers {
|
||||
first: "cfi".to_string(),
|
||||
|
@ -1599,6 +1618,43 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
});
|
||||
}
|
||||
|
||||
// Canonical jump tables requires CFI.
|
||||
if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
|
||||
if !sess.is_sanitizer_cfi_enabled() {
|
||||
sess.emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
|
||||
}
|
||||
}
|
||||
|
||||
// LLVM CFI pointer generalization requires CFI or KCFI.
|
||||
if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
|
||||
if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
|
||||
sess.emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
|
||||
}
|
||||
}
|
||||
|
||||
// LLVM CFI integer normalization requires CFI or KCFI.
|
||||
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
|
||||
sess.emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
|
||||
}
|
||||
}
|
||||
|
||||
// LTO unit splitting requires LTO.
|
||||
if sess.is_split_lto_unit_enabled()
|
||||
&& !(sess.lto() == config::Lto::Fat
|
||||
|| sess.lto() == config::Lto::Thin
|
||||
|| sess.opts.cg.linker_plugin_lto.enabled())
|
||||
{
|
||||
sess.emit_err(errors::SplitLtoUnitRequiresLto);
|
||||
}
|
||||
|
||||
// VFE requires LTO.
|
||||
if sess.lto() != config::Lto::Fat {
|
||||
if sess.opts.unstable_opts.virtual_function_elimination {
|
||||
sess.emit_err(errors::UnstableVirtualFunctionElimination);
|
||||
}
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.stack_protector != StackProtector::None {
|
||||
if !sess.target.options.supports_stack_protector {
|
||||
sess.emit_warning(errors::StackProtectorNotSupportedForTarget {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue