Skip to content

Commit 5ad7a64

Browse files
committed
Add fine-grained LLVM CFI support to the Rust compiler
This commit 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).
1 parent 5b8cf49 commit 5ad7a64

24 files changed

+1647
-136
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4441,6 +4441,7 @@ dependencies = [
44414441
name = "rustc_symbol_mangling"
44424442
version = "0.0.0"
44434443
dependencies = [
4444+
"bitflags",
44444445
"punycode",
44454446
"rustc-demangle",
44464447
"rustc_data_structures",

compiler/rustc_codegen_gcc/src/builder.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -784,16 +784,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
784784
// TODO(antoyo)
785785
}
786786

787-
fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
788-
// Unsupported.
789-
}
790-
791-
fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
792-
// Unsupported.
793-
self.context.new_rvalue_from_int(self.int_type, 0)
794-
}
795-
796-
797787
fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
798788
self.store_with_flags(val, ptr, align, MemFlags::empty())
799789
}

compiler/rustc_codegen_gcc/src/type_.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::convert::TryInto;
22

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

291291
(result, packed)
292292
}
293+
294+
impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
295+
fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) {
296+
// Unsupported.
297+
}
298+
299+
fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
300+
// Unsupported.
301+
self.context.new_rvalue_from_int(self.int_type, 0)
302+
}
303+
}

compiler/rustc_codegen_llvm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ rustc_middle = { path = "../rustc_middle" }
1818
rustc-demangle = "0.1.21"
1919
rustc_attr = { path = "../rustc_attr" }
2020
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
21-
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
2221
rustc_data_structures = { path = "../rustc_data_structures" }
2322
rustc_errors = { path = "../rustc_errors" }
2423
rustc_fs_util = { path = "../rustc_fs_util" }
@@ -30,6 +29,7 @@ rustc_metadata = { path = "../rustc_metadata" }
3029
rustc_query_system = { path = "../rustc_query_system" }
3130
rustc_session = { path = "../rustc_session" }
3231
rustc_serialize = { path = "../rustc_serialize" }
32+
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
3333
rustc_target = { path = "../rustc_target" }
3434
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
3535
rustc_ast = { path = "../rustc_ast" }

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -626,32 +626,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
626626
}
627627
}
628628

629-
fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
630-
let typeid_metadata = self.typeid_metadata(typeid);
631-
let v = [self.const_usize(0), typeid_metadata];
632-
unsafe {
633-
llvm::LLVMGlobalSetMetadata(
634-
function,
635-
llvm::MD_type as c_uint,
636-
llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
637-
self.cx.llcx,
638-
v.as_ptr(),
639-
v.len() as c_uint,
640-
)),
641-
)
642-
}
643-
}
644-
645-
fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
646-
unsafe {
647-
llvm::LLVMMDStringInContext(
648-
self.cx.llcx,
649-
typeid.as_ptr() as *const c_char,
650-
typeid.as_bytes().len() as c_uint,
651-
)
652-
}
653-
}
654-
655629
fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
656630
self.store_with_flags(val, ptr, align, MemFlags::empty())
657631
}

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ use crate::llvm;
1818
use crate::llvm::AttributePlace::Function;
1919
use crate::type_::Type;
2020
use crate::value::Value;
21+
use rustc_codegen_ssa::traits::TypeMembershipMethods;
2122
use rustc_middle::ty::Ty;
23+
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
2224
use smallvec::SmallVec;
2325
use tracing::debug;
2426

@@ -97,6 +99,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
9799
fn_abi.llvm_type(self),
98100
);
99101
fn_abi.apply_attrs_llfn(self, llfn);
102+
103+
if self.tcx.sess.is_sanitizer_cfi_enabled() {
104+
let typeid = typeid_for_fnabi(self.tcx, fn_abi);
105+
self.set_type_metadata(llfn, typeid);
106+
}
107+
100108
llfn
101109
}
102110

compiler/rustc_codegen_llvm/src/type_.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_target::abi::{AddressSpace, Align, Integer, Size};
1919
use std::fmt;
2020
use std::ptr;
2121

22-
use libc::c_uint;
22+
use libc::{c_char, c_uint};
2323

2424
impl PartialEq for Type {
2525
fn eq(&self, other: &Self) -> bool {
@@ -289,3 +289,31 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
289289
ty.llvm_type(self)
290290
}
291291
}
292+
293+
impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
294+
fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
295+
let typeid_metadata = self.typeid_metadata(typeid);
296+
let v = [self.const_usize(0), typeid_metadata];
297+
unsafe {
298+
llvm::LLVMGlobalSetMetadata(
299+
function,
300+
llvm::MD_type as c_uint,
301+
llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
302+
self.llcx,
303+
v.as_ptr(),
304+
v.len() as c_uint,
305+
)),
306+
)
307+
}
308+
}
309+
310+
fn typeid_metadata(&self, typeid: String) -> &'ll Value {
311+
unsafe {
312+
llvm::LLVMMDStringInContext(
313+
self.llcx,
314+
typeid.as_ptr() as *const c_char,
315+
typeid.len() as c_uint,
316+
)
317+
}
318+
}
319+
}

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
2020
use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
2121
use rustc_span::source_map::Span;
2222
use rustc_span::{sym, Symbol};
23-
use rustc_symbol_mangling::typeid_for_fnabi;
23+
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
2424
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
2525
use rustc_target::abi::{self, HasDataLayout, InitKind, WrappingRange};
2626
use rustc_target::spec::abi::Abi;
@@ -920,7 +920,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
920920
// FIXME(rcvalle): Add support for generalized identifiers.
921921
// FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
922922
let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
923-
let typeid_metadata = bx.typeid_metadata(typeid);
923+
let typeid_metadata = self.cx.typeid_metadata(typeid);
924924

925925
// Test whether the function pointer is associated with the type identifier.
926926
let cond = bx.type_test(fn_ptr, typeid_metadata);

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use rustc_middle::mir;
33
use rustc_middle::mir::interpret::ErrorHandled;
44
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
55
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable};
6-
use rustc_symbol_mangling::typeid_for_fnabi;
76
use rustc_target::abi::call::{FnAbi, PassMode};
87

98
use std::iter;
@@ -247,13 +246,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
247246
for (bb, _) in traversal::reverse_postorder(&mir) {
248247
fx.codegen_block(bb);
249248
}
250-
251-
// For backends that support CFI using type membership (i.e., testing whether a given pointer
252-
// is associated with a type identifier).
253-
if cx.tcx().sess.is_sanitizer_cfi_enabled() {
254-
let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
255-
bx.type_metadata(llfn, typeid);
256-
}
257249
}
258250

259251
/// Produces, for each argument, a `Value` pointing at the

compiler/rustc_codegen_ssa/src/traits/builder.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,6 @@ pub trait BuilderMethods<'a, 'tcx>:
160160

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

166164
fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
167165
fn store_with_flags(

0 commit comments

Comments
 (0)