Skip to content

KCFI: Add KCFI arity indicator support #138368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO
codegen_llvm_run_passes = failed to run LLVM passes
codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err}

codegen_llvm_sanitizer_kcfi_arity_requires_llvm_21_0_0 = `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.

codegen_llvm_sanitizer_memtag_requires_mte =
`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`

Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,22 @@ pub(crate) unsafe fn create_module<'ll>(
pfe.prefix().into(),
);
}

// Add "kcfi-arity" module flag if KCFI arity indicator is enabled. (See
// https://github.com/llvm/llvm-project/pull/117121.)
if sess.is_sanitizer_kcfi_arity_enabled() {
// KCFI arity indicator requires LLVM 21.0.0 or later.
if llvm_version < (21, 0, 0) {
tcx.dcx().emit_err(crate::errors::SanitizerKcfiArityRequiresLLVM2100);
}

llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"kcfi-arity",
1,
);
}
}

// Control Flow Guard is currently only supported by MSVC and LLVM on Windows.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_llvm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,7 @@ pub(crate) struct MismatchedDataLayout<'a> {
pub(crate) struct FixedX18InvalidArch<'a> {
pub arch: &'a str,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_sanitizer_kcfi_arity_requires_llvm_21_0_0)]
pub(crate) struct SanitizerKcfiArityRequiresLLVM2100;
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
tracked!(sanitizer_cfi_normalize_integers, Some(true));
tracked!(sanitizer_dataflow_abilist, vec![String::from("/rustc/abc")]);
tracked!(sanitizer_kcfi_arity, Some(true));
tracked!(sanitizer_memory_track_origins, 2);
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
tracked!(saturating_float_casts, Some(true));
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Cli

session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`

session_sanitizer_kcfi_arity_requires_kcfi = `-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`

session_sanitizer_kcfi_requires_panic_abort = `-Z sanitizer=kcfi` requires `-C panic=abort`

session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_session/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi;
#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi;

#[derive(Diagnostic)]
#[diag(session_sanitizer_kcfi_arity_requires_kcfi)]
pub(crate) struct SanitizerKcfiArityRequiresKcfi;

#[derive(Diagnostic)]
#[diag(session_sanitizer_kcfi_requires_panic_abort)]
pub(crate) struct SanitizerKcfiRequiresPanicAbort;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2443,6 +2443,8 @@ written to standard error output)"),
"enable normalizing integer types (default: no)"),
sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
"additional ABI list files that control how shadow parameters are passed (comma separated)"),
sanitizer_kcfi_arity: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable KCFI arity indicator (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],
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,10 @@ impl Session {
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
}

pub fn is_sanitizer_kcfi_arity_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_kcfi_arity == Some(true)
}

pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
}
Expand Down Expand Up @@ -1211,6 +1215,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}
}

// KCFI arity indicator requires KCFI.
if sess.is_sanitizer_kcfi_arity_enabled() && !sess.is_sanitizer_kcfi_enabled() {
sess.dcx().emit_err(errors::SanitizerKcfiArityRequiresKcfi);
}

// 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()) {
Expand Down
61 changes: 61 additions & 0 deletions tests/assembly/sanitizer/kcfi/emit-arity-indicator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Verifies that KCFI arity indicator is emitted.
//
//@ add-core-stubs
//@ revisions: x86_64
//@ assembly-output: emit-asm
//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -Cllvm-args=-x86-asm-syntax=intel -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity -Copt-level=0
//@ [x86_64] needs-llvm-components: x86
//@ min-llvm-version: 21.0.0

#![crate_type = "lib"]

pub fn add_one(x: i32) -> i32 {
// CHECK-LABEL: __cfi__{{.*}}7add_one{{.*}}:
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: mov ecx, 2628068948
x + 1
}

pub fn add_two(x: i32, _y: i32) -> i32 {
// CHECK-LABEL: __cfi__{{.*}}7add_two{{.*}}:
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: mov edx, 2505940310
x + 2
}

pub fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
// CHECK-LABEL: __cfi__{{.*}}8do_twice{{.*}}:
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: nop
// CHECK-NEXT: mov edx, 653723426
f(arg) + f(arg)
}
19 changes: 19 additions & 0 deletions tests/codegen/sanitizer/kcfi/add-kcfi-arity-flag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Verifies that "kcfi-arity" module flag is added.
//
//@ add-core-stubs
//@ revisions: x86_64
//@ [x86_64] compile-flags: --target x86_64-unknown-none
//@ [x86_64] needs-llvm-components: x86
//@ compile-flags: -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity
//@ min-llvm-version: 21.0.0

#![feature(no_core, lang_items)]
#![crate_type = "lib"]
#![no_core]

extern crate minicore;
use minicore::*;

pub fn foo() {}

// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-arity", i32 1}
9 changes: 9 additions & 0 deletions tests/ui/sanitizer/kcfi-arity-requires-kcfi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Verifies that `-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`.
//
//@ needs-sanitizer-kcfi
//@ compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer-kcfi-arity

//~? ERROR `-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`
#![feature(no_core)]
#![no_core]
#![no_main]
4 changes: 4 additions & 0 deletions tests/ui/sanitizer/kcfi-arity-requires-kcfi.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
error: `-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`

error: aborting due to 1 previous error

11 changes: 11 additions & 0 deletions tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Verifies that `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.
//
//@ needs-sanitizer-kcfi
//@ compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Cpanic=abort -Zsanitizer=kcfi -Zsanitizer-kcfi-arity
//@ build-fail
//@ max-llvm-major-version: 20

//~? ERROR `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.
#![feature(no_core)]
#![no_core]
#![no_main]
4 changes: 4 additions & 0 deletions tests/ui/sanitizer/kcfi-arity-requires-llvm-21-0-0.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
error: `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.

error: aborting due to 1 previous error

Loading