Skip to content

Commit 8a6c907

Browse files
committed
[PAC] Propagate function pointer type discrimination through get_fn_addr call sites
Fill in function pointer type discriminators logic across remaining `get_fn_addr` call sites and explicitly avoid applying it where discrimination is not meaningful. Some uses of `get_fn_addr` are intentionally left unsigned, including the EH personality function, entry wrappers, and compiler-generated Rust ABI shims.
1 parent c035be4 commit 8a6c907

4 files changed

Lines changed: 91 additions & 25 deletions

File tree

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,18 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
977977

978978
let tcx = self.tcx;
979979
let llfn = match tcx.lang_items().eh_personality() {
980+
// We intentionally do not apply pointer authentication (and/or function type
981+
// discriminators to the EH personality function).
982+
//
983+
// Although `get_fn_addr` normally produces a signed function pointer for
984+
// externally-callable functions, the EH personality is not an indirect call
985+
// target in the SSA sense. Instead, it is a compile-time constant attached to
986+
// the Function object (via LLVM's `setPersonalityFn`) and consumed only by
987+
// exception handling metadata generation (landing pads / unwind tables).
988+
// LLVM never loads or invokes the personality via a function pointer value;
989+
// it is not part of the program's call graph or data flow.
990+
// It's backend's responsibility to apply ABI-specific personality signing
991+
// when emitting the pointer in the object file.
980992
Some(def_id) if name.is_none() => self.get_fn_addr(
981993
ty::Instance::expect_resolve(
982994
tcx,
@@ -985,7 +997,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
985997
ty::List::empty(),
986998
DUMMY_SP,
987999
),
988-
tcx.sess.pointer_authentication_functions(),
1000+
None,
9891001
),
9901002
_ => {
9911003
let name = name.unwrap_or("rust_eh_personality");

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::time::{Duration, Instant};
44
use std::{cmp, iter};
55

66
use itertools::Itertools;
7-
use rustc_abi::FIRST_VARIANT;
7+
use rustc_abi::{ExternAbi, FIRST_VARIANT};
88
use rustc_ast::expand::allocator::{
99
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorMethodInput,
1010
AllocatorTy,
@@ -515,8 +515,18 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
515515
// We want to create the wrapper only when the codegen unit is the primary one
516516
return None;
517517
}
518-
519-
let main_llfn = cx.get_fn_addr(instance, cx.sess().pointer_authentication_functions());
518+
// No function pointer signing / type discriminator is needed here. Although `get_fn_addr` is
519+
// used to obtain function pointers, both the user's `main` and `LangItem::Start` use the Rust
520+
// ABI (currently pointer authentication is only supported for C/System ABI). The same applies
521+
// to the logic in `create_entry_fn` further below.
522+
assert!(
523+
!matches!(
524+
cx.tcx().fn_sig(main_def_id).skip_binder().abi(),
525+
ExternAbi::C { .. } | ExternAbi::System { .. }
526+
),
527+
"entry wrapper assumes Rust ABI"
528+
);
529+
let main_llfn = cx.get_fn_addr(instance, /* pointer_auth_schema */ None);
520530

521531
let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
522532
return Some(entry_fn);
@@ -577,8 +587,16 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
577587
cx.tcx().mk_args(&[main_ret_ty.into()]),
578588
DUMMY_SP,
579589
);
580-
let start_fn =
581-
cx.get_fn_addr(start_instance, cx.sess().pointer_authentication_functions());
590+
// Start instance doesn't require signing, as it uses Rust ABI, hence pass `None` to
591+
// `get_fn_addr`.
592+
assert!(
593+
!matches!(
594+
cx.tcx().fn_sig(start_instance.def_id()).skip_binder().abi(),
595+
ExternAbi::C { .. } | ExternAbi::System { .. }
596+
),
597+
"LangItem::Start unexpectedly uses the C/System ABI",
598+
);
599+
let start_fn = cx.get_fn_addr(start_instance, None);
582600

583601
let i8_ty = cx.type_i8();
584602
let arg_sigpipe = bx.const_u8(sigpipe);

compiler/rustc_codegen_ssa/src/common.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use rustc_hir::LangItem;
44
use rustc_hir::attrs::PeImportNameType;
55
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
6+
use rustc_middle::ptrauth::ptrauth_clone_discriminated_schema_for;
67
use rustc_middle::ty::layout::TyAndLayout;
78
use rustc_middle::ty::{self, Instance, ScalarInt, TyCtxt};
89
use rustc_middle::{bug, span_bug};
@@ -118,11 +119,20 @@ pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
118119
let tcx = bx.tcx();
119120
let def_id = tcx.require_lang_item(li, span);
120121
let instance = ty::Instance::mono(tcx, def_id);
121-
(
122-
bx.fn_abi_of_instance(instance, ty::List::empty()),
123-
bx.get_fn_addr(instance, tcx.sess.pointer_authentication_functions()),
124-
instance,
125-
)
122+
123+
let schema = if bx.sess().pointer_authentication_fn_ptr_type_discrimination() {
124+
// It is unlikely that any of LangItem will follow the extern C/System ABI, but it future
125+
// proofs the implementation.
126+
ptrauth_clone_discriminated_schema_for(
127+
bx.tcx(),
128+
bx.sess().pointer_authentication_functions(),
129+
instance,
130+
)
131+
} else {
132+
bx.sess().pointer_authentication_functions().clone()
133+
};
134+
135+
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance, schema), instance)
126136
}
127137

128138
pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_hir::lang_items::LangItem;
1313
use rustc_lint_defs::builtin::TAIL_CALL_TRACK_CALLER;
1414
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, Scalar};
1515
use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason};
16+
use rustc_middle::ptrauth::ptrauth_clone_discriminated_schema_for;
1617
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout, ValidityRequirement};
1718
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1819
use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
@@ -695,12 +696,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
695696
virtual_drop,
696697
)
697698
}
698-
_ => (
699-
false,
700-
bx.get_fn_addr(drop_fn, bx.sess().pointer_authentication_functions()),
701-
bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
702-
drop_fn,
703-
),
699+
_ => {
700+
let schema = if bx.sess().pointer_authentication_fn_ptr_type_discrimination() {
701+
ptrauth_clone_discriminated_schema_for(
702+
bx.tcx(),
703+
bx.sess().pointer_authentication_functions(),
704+
drop_fn,
705+
)
706+
} else {
707+
bx.sess().pointer_authentication_functions().clone()
708+
};
709+
(
710+
false,
711+
bx.get_fn_addr(drop_fn, schema),
712+
bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
713+
drop_fn,
714+
)
715+
}
704716
};
705717

706718
// We generate a null check for the drop_fn. This saves a bunch of relocations being
@@ -1112,14 +1124,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11121124
generic_args.no_bound_vars().unwrap(),
11131125
)
11141126
.unwrap();
1127+
let schema =
1128+
if bx.sess().pointer_authentication_fn_ptr_type_discrimination() {
1129+
ptrauth_clone_discriminated_schema_for(
1130+
bx.tcx(),
1131+
bx.sess().pointer_authentication_functions(),
1132+
instance,
1133+
)
1134+
} else {
1135+
bx.sess().pointer_authentication_functions().clone()
1136+
};
11151137

1116-
(
1117-
None,
1118-
Some(bx.get_fn_addr(
1119-
instance,
1120-
bx.sess().pointer_authentication_functions(),
1121-
)),
1122-
)
1138+
(None, Some(bx.get_fn_addr(instance, schema)))
11231139
}
11241140
_ => (Some(instance), None),
11251141
}
@@ -1433,7 +1449,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14331449

14341450
let fn_ptr = match (instance, llfn) {
14351451
(Some(instance), None) => {
1436-
bx.get_fn_addr(instance, bx.sess().pointer_authentication_functions())
1452+
let schema = if bx.sess().pointer_authentication_fn_ptr_type_discrimination() {
1453+
ptrauth_clone_discriminated_schema_for(
1454+
bx.tcx(),
1455+
bx.sess().pointer_authentication_functions(),
1456+
instance,
1457+
)
1458+
} else {
1459+
bx.sess().pointer_authentication_functions().clone()
1460+
};
1461+
1462+
bx.get_fn_addr(instance, schema)
14371463
}
14381464
(_, Some(llfn)) => llfn,
14391465
_ => span_bug!(fn_span, "no instance or llfn for call"),

0 commit comments

Comments
 (0)