Skip to content

Commit

Permalink
Auto merge of #95548 - rcvalle:rust-cfi-2, r=nagisa
Browse files Browse the repository at this point in the history
Add fine-grained LLVM CFI support to the Rust compiler

This PR improves the LLVM Control Flow Integrity (CFI) support in the Rust compiler by providing forward-edge control flow protection for Rust-compiled code only by aggregating function pointers in groups identified by their return and parameter types.

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) will be provided in later work as part of this project by identifying C char and integer type uses at the time types are encoded (see Type metadata in the design document in the tracking issue #89653).

LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).

Thank you again, `@eddyb,` `@nagisa,` `@pcc,` and `@tmiasko` for all the help!
  • Loading branch information
bors committed Jul 24, 2022
2 parents fcad918 + f792f26 commit db8086e
Show file tree
Hide file tree
Showing 25 changed files with 1,732 additions and 165 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4519,6 +4519,7 @@ dependencies = [
name = "rustc_symbol_mangling"
version = "0.0.0"
dependencies = [
"bitflags",
"punycode",
"rustc-demangle",
"rustc_data_structures",
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,16 +784,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo)
}

fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
// Unsupported.
}

fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
// Unsupported.
self.context.new_rvalue_from_int(self.int_type, 0)
}


fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_codegen_gcc/src/type_.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::convert::TryInto;

use gccjit::{RValue, Struct, Type};
use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods};
use rustc_codegen_ssa::common::TypeKind;
use rustc_middle::{bug, ty};
use rustc_middle::ty::layout::TyAndLayout;
Expand Down Expand Up @@ -290,3 +290,14 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout

(result, packed)
}

impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) {
// Unsupported.
}

fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
// Unsupported.
self.context.new_rvalue_from_int(self.int_type, 0)
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ rustc_middle = { path = "../rustc_middle" }
rustc-demangle = "0.1.21"
rustc_attr = { path = "../rustc_attr" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fs_util = { path = "../rustc_fs_util" }
Expand All @@ -30,6 +29,7 @@ rustc_metadata = { path = "../rustc_metadata" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_ast = { path = "../rustc_ast" }
Expand Down
26 changes: 0 additions & 26 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,32 +626,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}

fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
let typeid_metadata = self.typeid_metadata(typeid);
let v = [self.const_usize(0), typeid_metadata];
unsafe {
llvm::LLVMGlobalSetMetadata(
function,
llvm::MD_type as c_uint,
llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
self.cx.llcx,
v.as_ptr(),
v.len() as c_uint,
)),
)
}
}

fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
unsafe {
llvm::LLVMMDStringInContext(
self.cx.llcx,
typeid.as_ptr() as *const c_char,
typeid.as_bytes().len() as c_uint,
)
}
}

fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_codegen_llvm/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ use crate::llvm;
use crate::llvm::AttributePlace::Function;
use crate::type_::Type;
use crate::value::Value;
use rustc_codegen_ssa::traits::TypeMembershipMethods;
use rustc_middle::ty::Ty;
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
use smallvec::SmallVec;
use tracing::debug;

Expand Down Expand Up @@ -97,6 +99,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
fn_abi.llvm_type(self),
);
fn_abi.apply_attrs_llfn(self, llfn);

if self.tcx.sess.is_sanitizer_cfi_enabled() {
let typeid = typeid_for_fnabi(self.tcx, fn_abi);
self.set_type_metadata(llfn, typeid);
}

llfn
}

Expand Down
30 changes: 29 additions & 1 deletion compiler/rustc_codegen_llvm/src/type_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rustc_target::abi::{AddressSpace, Align, Integer, Size};
use std::fmt;
use std::ptr;

use libc::c_uint;
use libc::{c_char, c_uint};

impl PartialEq for Type {
fn eq(&self, other: &Self) -> bool {
Expand Down Expand Up @@ -289,3 +289,31 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
ty.llvm_type(self)
}
}

impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
let typeid_metadata = self.typeid_metadata(typeid);
let v = [self.const_usize(0), typeid_metadata];
unsafe {
llvm::LLVMGlobalSetMetadata(
function,
llvm::MD_type as c_uint,
llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
self.llcx,
v.as_ptr(),
v.len() as c_uint,
)),
)
}
}

fn typeid_metadata(&self, typeid: String) -> &'ll Value {
unsafe {
llvm::LLVMMDStringInContext(
self.llcx,
typeid.as_ptr() as *const c_char,
typeid.len() as c_uint,
)
}
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
Expand Down Expand Up @@ -918,7 +918,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// FIXME(rcvalle): Add support for generalized identifiers.
// FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
let typeid_metadata = bx.typeid_metadata(typeid);
let typeid_metadata = self.cx.typeid_metadata(typeid);

// Test whether the function pointer is associated with the type identifier.
let cond = bx.type_test(fn_ptr, typeid_metadata);
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable};
use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{FnAbi, PassMode};

use std::iter;
Expand Down Expand Up @@ -247,13 +246,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
for (bb, _) in traversal::reverse_postorder(&mir) {
fx.codegen_block(bb);
}

// For backends that support CFI using type membership (i.e., testing whether a given pointer
// is associated with a type identifier).
if cx.tcx().sess.is_sanitizer_cfi_enabled() {
let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
bx.type_metadata(llfn, typeid);
}
}

/// Produces, for each argument, a `Value` pointing at the
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,6 @@ pub trait BuilderMethods<'a, 'tcx>:

fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
fn nonnull_metadata(&mut self, load: Self::Value);
fn type_metadata(&mut self, function: Self::Function, typeid: String);
fn typeid_metadata(&mut self, typeid: String) -> Self::Value;

fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
fn store_with_flags(
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ pub use self::intrinsic::IntrinsicCallMethods;
pub use self::misc::MiscMethods;
pub use self::statics::{StaticBuilderMethods, StaticMethods};
pub use self::type_::{
ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMembershipMethods,
TypeMethods,
};
pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};

Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_codegen_ssa/src/traits/type_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
) -> Self::Type;
}

// For backends that support CFI using type membership (i.e., testing whether a given pointer is
// associated with a type identifier).
pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> {
fn set_type_metadata(&self, function: Self::Function, typeid: String);
fn typeid_metadata(&self, typeid: String) -> Self::Value;
}

pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
fn store_fn_arg(
&mut self,
Expand All @@ -133,6 +140,12 @@ pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type;
}

pub trait TypeMethods<'tcx>: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
pub trait TypeMethods<'tcx>:
DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx>
{
}

impl<'tcx, T> TypeMethods<'tcx> for T where Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
impl<'tcx, T> TypeMethods<'tcx> for T where
Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> + TypeMembershipMethods<'tcx>
{
}
1 change: 1 addition & 0 deletions compiler/rustc_symbol_mangling/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
doctest = false

[dependencies]
bitflags = "1.2.1"
tracing = "0.1"
punycode = "0.4.0"
rustc-demangle = "0.1.21"
Expand Down
9 changes: 2 additions & 7 deletions compiler/rustc_symbol_mangling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,16 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::config::SymbolManglingVersion;
use rustc_target::abi::call::FnAbi;

use tracing::debug;

mod legacy;
mod v0;

pub mod test;
pub mod typeid;

/// This function computes the symbol name for the given `instance` and the
/// given instantiating crate. That is, if you know that instance X is
Expand Down Expand Up @@ -150,11 +150,6 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty
ty::SymbolName::new(tcx, &symbol_name)
}

/// This function computes the typeid for the given function ABI.
pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
v0::mangle_typeid_for_fnabi(tcx, fn_abi)
}

pub fn typeid_for_trait_ref<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyExistentialTraitRef<'tcx>,
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_symbol_mangling/src/typeid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// For more information about type metadata and type metadata identifiers for cross-language LLVM
// CFI support, see Type metadata in the design document in the tracking issue #89653.

use rustc_middle::ty::{FnSig, Ty, TyCtxt};
use rustc_target::abi::call::FnAbi;

mod typeid_itanium_cxx_abi;
use typeid_itanium_cxx_abi::TypeIdOptions;

/// Returns a type metadata identifier for the specified FnAbi.
pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS)
}

/// Returns a type metadata identifier for the specified FnSig.
pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String {
typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS)
}
Loading

0 comments on commit db8086e

Please sign in to comment.