Skip to content

Commit

Permalink
CFI: Fix (3) of core and std have explict CFI violations
Browse files Browse the repository at this point in the history
Fixes (3) of #115199 by transforming function items, closures, and Fn
trait objects into function pointers.
  • Loading branch information
rcvalle committed Oct 26, 2023
1 parent 07a4b7e commit 3e28128
Show file tree
Hide file tree
Showing 8 changed files with 606 additions and 583 deletions.
62 changes: 62 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Expand Up @@ -744,6 +744,52 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
}

impl<'tcx> List<ty::PolyExistentialPredicate<'tcx>> {
/// Returns the list of arguments if principal is an Fn trait.
pub fn fn_trait_args(&self, tcx: TyCtxt<'tcx>) -> Option<&List<Ty<'tcx>>> {
if self.is_fn_trait(tcx) {
if let Some(args) = self.principal_args() && !args.is_empty() && args[0].expect_ty().is_tuple() {
Some(args[0].expect_ty().tuple_fields())
} else {
bug!("fn_trait_args: unexpected non-tuple arg `{:?}`", self.principal_args());
}
} else {
None
}
}

/// Returns the output if principal is an Fn trait.
pub fn fn_trait_output(&self, tcx: TyCtxt<'tcx>) -> Option<Ty<'tcx>> {
if self.is_fn_trait(tcx) {
if let Some(projection) = self.projection_bounds().next() && let Some(ty) = projection.skip_binder().term.ty() {
Some(ty)
} else {
bug!("fn_trait_output: unexpected non-term projection `{:?}`", self.projection_bounds().next());
}
} else {
None
}
}

/// Returns the signature if principal is an Fn trait.
pub fn fn_trait_sig(&self, tcx: TyCtxt<'tcx>) -> Option<FnSig<'tcx>> {
if self.is_fn_trait(tcx) {
Some(tcx.mk_fn_sig(
self.fn_trait_args(tcx).unwrap(),
self.fn_trait_output(tcx).unwrap(),
false,
hir::Unsafety::Normal,
Abi::Rust,
))
} else {
None
}
}

/// Returns true if principal is an Fn trait.
pub fn is_fn_trait(&self, tcx: TyCtxt<'tcx>) -> bool {
if let Some(principal) = self.principal() && tcx.is_fn_trait(principal.skip_binder().def_id) { true } else { false }
}

/// Returns the "principal `DefId`" of this set of existential predicates.
///
/// A Rust trait object type consists (in addition to a lifetime bound)
Expand Down Expand Up @@ -778,6 +824,12 @@ impl<'tcx> List<ty::PolyExistentialPredicate<'tcx>> {
.transpose()
}

/// Returns the principal list of arguments.
pub fn principal_args(&self) -> Option<&List<GenericArg<'tcx>>> {
self.principal().map(|trait_ref| trait_ref.skip_binder().args)
}

/// Returns the principal DefId.
pub fn principal_def_id(&self) -> Option<DefId> {
self.principal().map(|trait_ref| trait_ref.skip_binder().def_id)
}
Expand Down Expand Up @@ -2269,6 +2321,11 @@ impl<'tcx> Ty<'tcx> {
self.0.0.flags
}

#[inline]
pub fn is_tuple(self) -> bool {
matches!(self.kind(), Tuple(..))
}

#[inline]
pub fn is_unit(self) -> bool {
match self.kind() {
Expand Down Expand Up @@ -2622,6 +2679,11 @@ impl<'tcx> Ty<'tcx> {
matches!(self.kind(), FnDef(..) | FnPtr(_))
}

#[inline]
pub fn is_fn_def(self) -> bool {
matches!(self.kind(), FnDef(..))
}

#[inline]
pub fn is_fn_ptr(self) -> bool {
matches!(self.kind(), FnPtr(_))
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_symbol_mangling/src/lib.rs
Expand Up @@ -91,6 +91,8 @@
#![cfg_attr(not(bootstrap), doc(rust_logo))]
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
#![cfg_attr(not(bootstrap), allow(internal_features))]
#![feature(iter_order_by)]
#![feature(let_chains)]
#![feature(never_type)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
Expand Down
64 changes: 37 additions & 27 deletions compiler/rustc_symbol_mangling/src/typeid.rs
Expand Up @@ -4,7 +4,7 @@
/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
/// see design document in the tracking issue #89653.
use bitflags::bitflags;
use rustc_middle::ty::{FnSig, Instance, Ty, TyCtxt};
use rustc_middle::ty::{Instance, List, Ty, TyCtxt};
use rustc_target::abi::call::FnAbi;
use std::hash::Hasher;
use twox_hash::XxHash64;
Expand All @@ -26,16 +26,11 @@ pub fn typeid_for_fnabi<'tcx>(
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
options: TypeIdOptions,
) -> String {
typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options)
}

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

/// Returns a type metadata identifier for the specified Instance.
Expand All @@ -44,7 +39,16 @@ pub fn typeid_for_instance<'tcx>(
instance: &Instance<'tcx>,
options: TypeIdOptions,
) -> String {
typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
let fn_abi = tcx
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, List::empty())))
.unwrap_or_else(|instance| {
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
});
typeid_itanium_cxx_abi::typeid_for_fnabi(
tcx,
&typeid_itanium_cxx_abi::transform_fnabi(tcx, &fn_abi, options, Some(instance)),
options,
)
}

/// Returns a KCFI type metadata identifier for the specified FnAbi.
Expand All @@ -56,20 +60,14 @@ pub fn kcfi_typeid_for_fnabi<'tcx>(
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
let mut hash: XxHash64 = Default::default();
hash.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes());
hash.finish() as u32
}

/// Returns a KCFI type metadata identifier for the specified FnSig.
pub fn kcfi_typeid_for_fnsig<'tcx>(
tcx: TyCtxt<'tcx>,
fn_sig: &FnSig<'tcx>,
options: TypeIdOptions,
) -> u32 {
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
let mut hash: XxHash64 = Default::default();
hash.write(typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options).as_bytes());
hash.write(
typeid_itanium_cxx_abi::typeid_for_fnabi(
tcx,
&typeid_itanium_cxx_abi::transform_fnabi(tcx, &fn_abi, options, None),
options,
)
.as_bytes(),
);
hash.finish() as u32
}

Expand All @@ -79,9 +77,21 @@ pub fn kcfi_typeid_for_instance<'tcx>(
instance: &Instance<'tcx>,
options: TypeIdOptions,
) -> u32 {
let fn_abi = tcx
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, List::empty())))
.unwrap_or_else(|instance| {
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
});
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
let mut hash: XxHash64 = Default::default();
hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
hash.write(
typeid_itanium_cxx_abi::typeid_for_fnabi(
tcx,
&typeid_itanium_cxx_abi::transform_fnabi(tcx, &fn_abi, options, Some(instance)),
options,
)
.as_bytes(),
);
hash.finish() as u32
}

0 comments on commit 3e28128

Please sign in to comment.