Skip to content
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

TypeId: use a (v0) mangled type to remain sound in the face of hash collisions. #95845

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
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
Prev Previous commit
Next Next commit
codegen, symbol_mangling: prefix/move LLVM CFI functionality to avoid…
… confusion.
eddyb committed Apr 9, 2022
commit bb343600f777f605fa1db4890811ee89d308694a
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
@@ -783,11 +783,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo)
}

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

fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
fn llvm_cfi_typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
// Unsupported.
self.context.new_rvalue_from_int(self.int_type, 0)
}
8 changes: 5 additions & 3 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
@@ -621,8 +621,9 @@ 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);
// FIXME(eddyb) this does not belong in `Builder`, it's global.
fn llvm_cfi_type_metadata(&mut self, function: &'ll Value, typeid: String) {
let typeid_metadata = self.llvm_cfi_typeid_metadata(typeid);
let v = [self.const_usize(0), typeid_metadata];
unsafe {
llvm::LLVMGlobalSetMetadata(
@@ -637,7 +638,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}

fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
// FIXME(eddyb) this does not belong in `Builder`, it's global.
fn llvm_cfi_typeid_metadata(&mut self, typeid: String) -> Self::Value {
unsafe {
llvm::LLVMMDStringInContext(
self.cx.llcx,
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_symbol_mangling::llvm_cfi_typeid_for_fn_abi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
@@ -908,8 +908,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Emit type metadata and checks.
// 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 = llvm_cfi_typeid_for_fn_abi(bx.tcx(), fn_abi);
let typeid_metadata = bx.llvm_cfi_typeid_metadata(typeid);

// Test whether the function pointer is associated with the type identifier.
let cond = bx.type_test(fn_ptr, typeid_metadata);
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ 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};
use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_symbol_mangling::llvm_cfi_typeid_for_fn_abi;
use rustc_target::abi::call::{FnAbi, PassMode};

use std::iter;
@@ -252,8 +252,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// 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);
let typeid = llvm_cfi_typeid_for_fn_abi(cx.tcx(), fn_abi);
bx.llvm_cfi_type_metadata(llfn, typeid);
}
}

6 changes: 4 additions & 2 deletions compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
@@ -160,8 +160,10 @@ 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;

// FIXME(eddyb) these do not belong in `Builder`, they're global.
fn llvm_cfi_type_metadata(&mut self, function: Self::Function, typeid: String);
fn llvm_cfi_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(
37 changes: 34 additions & 3 deletions compiler/rustc_symbol_mangling/src/lib.rs
Original file line number Diff line number Diff line change
@@ -150,9 +150,40 @@ 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)
/// This function computes the LLVM CFI typeid for the given `FnAbi`.
pub fn llvm_cfi_typeid_for_fn_abi<'tcx>(
_tcx: TyCtxt<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> String {
// LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
// type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
// associated with a type identifier (i.e., test type membership).
//
// Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
// type metadata identifiers for function pointers. The typeinfo name encoding is a
// two-character code (i.e., “TS”) prefixed to the type encoding for the function.
//
// For cross-language LLVM CFI support, a compatible encoding must be used by either
//
// a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
// type encodings[4]), or at least types used at the FFI boundary.
// b. Reducing the types to the least common denominator between types used by Clang (or at
// least types used at the FFI boundary) and Rust compilers (if even possible).
// c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
// possibly other compilers).
//
// Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
// as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
// code. Option (c) would require changes to Clang to use the new ABI.
//
// [1] https://llvm.org/docs/TypeMetadata.html
// [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
// [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
// [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
//
// FIXME(rcvalle): See comment above.
let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
format!("typeid{}", arg_count)
}

/// Computes the symbol name for the given instance. This function will call
36 changes: 0 additions & 36 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@ use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
use rustc_span::symbol::kw;
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::Integer;
use rustc_target::spec::abi::Abi;

@@ -58,41 +57,6 @@ pub(super) fn mangle<'tcx>(
std::mem::take(&mut cx.out)
}

pub(super) fn mangle_typeid_for_fnabi<'tcx>(
bjorn3 marked this conversation as resolved.
Show resolved Hide resolved
_tcx: TyCtxt<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> String {
// LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
// type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
// associated with a type identifier (i.e., test type membership).
//
// Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
// type metadata identifiers for function pointers. The typeinfo name encoding is a
// two-character code (i.e., “TS”) prefixed to the type encoding for the function.
//
// For cross-language LLVM CFI support, a compatible encoding must be used by either
//
// a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
// type encodings[4]), or at least types used at the FFI boundary.
// b. Reducing the types to the least common denominator between types used by Clang (or at
// least types used at the FFI boundary) and Rust compilers (if even possible).
// c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
// possibly other compilers).
//
// Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
// as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
// code. Option (c) would require changes to Clang to use the new ABI.
//
// [1] https://llvm.org/docs/TypeMetadata.html
// [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
// [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
// [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
//
// FIXME(rcvalle): See comment above.
let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
format!("typeid{}", arg_count)
}

struct BinderLevel {
/// The range of distances from the root of what's
/// being printed, to the lifetimes in a binder.