diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b2ce873154bcc..92e939722b21c 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -25,8 +25,19 @@ use crate::llvm::{ self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, TypeKind, Value, const_ptr_auth, }; +/// Return true if the ABI of an `instance` is supported by pointer authentication (`extern "C"` and +/// `extern "system"`). +pub(crate) fn is_ptrauth_signed_fn<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { + let def_id = instance.def_id(); + matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) + && matches!( + tcx.fn_sig(def_id).skip_binder().abi(), + ExternAbi::C { .. } | ExternAbi::System { .. } + ) +} + pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( - cx: &CodegenCx<'ll, '_>, + cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, llfn: &'ll llvm::Value, schema: &PointerAuthSchema, @@ -35,16 +46,10 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( return llfn; } - // Only free functions or methods - let def_id = instance.def_id(); - if !matches!(cx.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - return llfn; - } - // Only C ABI - let abi = cx.tcx.fn_sig(def_id).skip_binder().abi(); - if !matches!(abi, ExternAbi::C { .. } | ExternAbi::System { .. }) { + if !is_ptrauth_signed_fn(cx.tcx, instance) { return llfn; } + let def_id = instance.def_id(); // Ignore LLVM intrinsics if llvm::get_value_name(llfn).starts_with(b"llvm.") { return llfn; @@ -54,8 +59,14 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( } let addr_diversity = match schema.is_address_discriminated { - PointerAuthAddressDiscriminator::HardwareAddress(true) => Some(llfn), + // Address discrimination blends in the address of the slot holding the pointer, that + // feature is unsupported. Treat it as a bug. + PointerAuthAddressDiscriminator::HardwareAddress(true) => { + bug!("address-discriminated function pointer schemas are not supported") + } PointerAuthAddressDiscriminator::HardwareAddress(false) => None, + // init/fini entries use a synthetic placeholder. If set, the loader will blend in the + // run-time address. PointerAuthAddressDiscriminator::Synthetic(val) => { let llval = cx.const_u64(val); let llty = cx.val_ty(llfn); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 33d48642812e6..219287e8bb826 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -9,8 +9,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar, - read_target_uint, + Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer, + Scalar as InterpScalar, read_target_uint, }; use rustc_middle::mono::MonoItem; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; @@ -19,8 +19,8 @@ use rustc_span::{Symbol, bug, span_bug}; use rustc_target::spec::Arch; use tracing::{debug, instrument, trace}; -use crate::common::CodegenCx; -use crate::diagnostics::SymbolAlreadyDefined; +use crate::common::{CodegenCx, is_ptrauth_signed_fn}; +use crate::diagnostics::{PtrauthUnsignedInitFiniEntry, SymbolAlreadyDefined}; use crate::llvm::{self, Type, Value, const_ptr_auth}; use crate::{base, debuginfo}; @@ -173,9 +173,42 @@ fn codegen_static_initializer<'ll, 'tcx>( } }) .unwrap_or(IsInitOrFini::No); + if let IsInitOrFini::Yes = is_in_init_fini { + check_init_fini_entries_are_signed(cx, def_id, alloc.inner()); + } Ok((const_alloc_to_llvm(cx, alloc.inner(), IsStatic::Yes, is_in_init_fini), alloc)) } +/// For pointer authentication the loader authenticates every entry of an init/fini array with the +/// init/fini schema, but only functions whose ABI is supported (see `is_ptrauth_signed_fn`) can be +/// signed. +/// Reject non supported entries instead of emitting entries that fail authentication when the +/// loader runs them. +fn check_init_fini_entries_are_signed<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + def_id: DefId, + alloc: &Allocation, +) { + if cx.sess().pointer_authentication_init_fini().is_none() { + return; + } + let section = cx.tcx.codegen_fn_attrs(def_id).link_section.map(|s| s.to_string()); + let mut reported = Vec::new(); + for &(_, prov) in alloc.provenance().ptrs().iter() { + if let GlobalAlloc::Function { instance, .. } = cx.tcx.global_alloc(prov.alloc_id()) + && !is_ptrauth_signed_fn(cx.tcx, instance) + && !reported.contains(&instance) + { + reported.push(instance); + cx.tcx.dcx().emit_err(PtrauthUnsignedInitFiniEntry { + span: cx.tcx.def_span(def_id), + function: cx.tcx.def_path_str(instance.def_id()), + section: section.clone().unwrap_or_default(), + }); + } + } +} + fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { // The target may require greater alignment for globals than the type does. // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index 19b2f68107e6c..38899ca58f405 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -18,6 +18,19 @@ pub(crate) struct SymbolAlreadyDefined<'a> { #[diag("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`")] pub(crate) struct SanitizerMemtagRequiresMte; +#[derive(Diagnostic)] +#[diag("`{$function}` is placed in `{$section}`, but pointer authentication does not sign its ABI")] +#[note( + "the loader authenticates every entry of `.init_array` and `.fini_array` with the init/fini signing schema, so an unsigned entry fails authentication when the loader runs it" +)] +#[help("declare `{$function}` as `extern \"C\"`")] +pub(crate) struct PtrauthUnsignedInitFiniEntry { + #[primary_span] + pub span: Span, + pub function: String, + pub section: String, +} + pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); impl Diagnostic<'_> for ParseTargetMachineConfig<'_> { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9bf2de0466233..b6108a9ecb006 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -110,8 +110,8 @@ pub enum PointerAuthDiscrimination { pub enum PointerAuthAddressDiscriminator { /// Enable/disable hardware address discrimination. HardwareAddress(bool), - /// Use a synthetic value. For instance init/fini entries can not the address of the arrays, - /// they must use a synthetic value of `1`. + /// Use a synthetic value. Address-discriminated init/fini entries use a placeholder value of + /// `1`, (LLVM's `ConstantPtrAuth::AddrDiscriminator_CtorsDtors`). Synthetic(u64), } @@ -158,6 +158,9 @@ pub struct PointerAuthConfig { pub function_pointers: Option, /// The ABI for function addresses in .init_array and .fini_array pub init_fini: Option, + /// Should init/fini entries be address discriminated? Kept apart from `init_fini`, as in Clang: + /// it is recorded in the PAuth ABI version even when init/fini signing is disabled. + pub init_fini_address_discrimination: bool, /// Use of pointer authentication intrinsics. pub intrinsics: bool, /// The following are used only for compatibility with C++ and control over generated abi @@ -177,6 +180,7 @@ impl PointerAuthConfig { aarch64_jump_table_hardening: true, function_pointers: Some(PointerAuthSchema::function_pointers_default(target)), init_fini: Some(PointerAuthSchema::init_fini_default(target)), + init_fini_address_discrimination: true, intrinsics: true, typeinfo_vt_ptr_discrimination: true, vt_ptr_addr_discrimination: true, @@ -215,13 +219,7 @@ impl PointerAuthConfig { | (u32::from(self.vt_ptr_addr_discrimination) << VT_PTR_ADDR_DISCR) | (u32::from(self.vt_ptr_type_discrimination) << VT_PTR_TYPE_DISCR) | (u32::from(self.init_fini.is_some()) << INIT_FINI) - | (u32::from(self.init_fini.as_ref().is_some_and(|schema| { - matches!( - schema.is_address_discriminated, - PointerAuthAddressDiscriminator::HardwareAddress(true) - | PointerAuthAddressDiscriminator::Synthetic(_) - ) - })) << INIT_FINI_ADDR_DISC) + | (u32::from(self.init_fini_address_discrimination) << INIT_FINI_ADDR_DISC) | (u32::from(self.elf_got) << GOT) | (u32::from(self.indirect_gotos) << GOTOS) | (u32::from(self.typeinfo_vt_ptr_discrimination) << TYPEINFO_VT_PTR_DISCR); @@ -275,16 +273,7 @@ impl PointerAuthConfig { } } PointerAuthOption::InitFiniAddressDiscrimination => { - if *enabled { - let schema = cfg - .init_fini - .get_or_insert_with(|| PointerAuthSchema::init_fini_default(target)); - schema.is_address_discriminated = - PointerAuthAddressDiscriminator::HardwareAddress(true); - } else if let Some(schema) = &mut cfg.init_fini { - schema.is_address_discriminated = - PointerAuthAddressDiscriminator::Synthetic(1); - } + cfg.init_fini_address_discrimination = *enabled } PointerAuthOption::Intrinsics => cfg.intrinsics = *enabled, @@ -296,6 +285,17 @@ impl PointerAuthConfig { } } + // With address discrimination an entry carries the placeholder address discriminator `1` + // (see `PointerAuthAddressDiscriminator::Synthetic`), and without it no address + // discriminator at all. + if let Some(schema) = &mut cfg.init_fini { + schema.is_address_discriminated = if cfg.init_fini_address_discrimination { + PointerAuthAddressDiscriminator::Synthetic(1) + } else { + PointerAuthAddressDiscriminator::HardwareAddress(false) + }; + } + Some(cfg) } pub fn fn_attrs(&self) -> Vec<&'static str> { diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md index 1118145a2097c..a2e0ca1e58ac3 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md @@ -370,9 +370,15 @@ disable a feature, where `` is one of: * `function-pointer-type-discrimination` - enable type discrimination for C function pointers * `indirect-gotos` - enable signing and authentication of indirect goto targets -* `init-fini` - enable signing of function pointers stored in init/fini arrays +* `init-fini` - enable signing of function pointers stored in init/fini arrays. + Only `extern "C"` and `extern "system"` functions are signed, so a static in + an `.init_array` or `.fini_array` section that points to a function of any + other ABI is rejected * `init-fini-address-discrimination` - enable address discrimination for - init/fini array entries + init/fini array entries (on by default). As in Clang, an entry is signed + with address diversity, so the loader blends in the address of the entry. + Also as in Clang, this option does not enable `init-fini`, and it sets its + bit of the PAuth ABI version even when `init-fini` is disabled * `intrinsics` - enable pointer authentication intrinsics * `return-addresses` - enable signing and authentication of return addresses * `typeinfo-vt-ptr-discrimination` - enable type/address discrimination for @@ -458,6 +464,7 @@ This target can be tested as normal with `x.py`. The following categories are supported (all present in tree): * Assembly tests * pauth-basic.rs + * pauth-init-fini.rs * LLVM IR/codegen tests * pauth-extern-c.rs * pauth-extern-c-direct-indirect-call.rs @@ -473,6 +480,7 @@ The following categories are supported (all present in tree): * enable_pointer_authentication_validation.rs * invalid_target_pointer_authentication.rs * type_discrimination_not_supported_pointer_authentication.rs + * init-fini-unsigned-abi.rs * incompatible_pauth.rs * Unit tests for siphash function: * compiler/rustc_middle/src/ptrauth/llvm_siphash/tests.rs @@ -489,6 +497,7 @@ x.py test --target aarch64-unknown-linux-pauthtest --force-rerun assembly-llvm \ codegen-llvm codegen-units coverage crashes incremental library mir-opt \ run-make rust_middle ui ui-fulldeps \ tests/assembly-llvm/pauth-basic.rs \ + tests/assembly-llvm/pauth-init-fini.rs \ tests/codegen-llvm/pauth/pauth-attr-cli-flags.rs \ tests/codegen-llvm/pauth/pauth-attr-special-funcs.rs \ tests/codegen-llvm/pauth/pauth-extern-c.rs \ @@ -502,6 +511,7 @@ x.py test --target aarch64-unknown-linux-pauthtest --force-rerun assembly-llvm \ tests/ui/pointer_authentication/enable_pointer_authentication_validation.rs \ tests/ui/pointer_authentication/invalid_target_pointer_authentication.rs \ tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.rs \ + tests/ui/pointer_authentication/init-fini-unsigned-abi.rs \ tests/ui/target_modifiers/incompatible_pauth.rs ``` diff --git a/tests/assembly-llvm/pauth-init-fini.rs b/tests/assembly-llvm/pauth-init-fini.rs new file mode 100644 index 0000000000000..de61546b77713 --- /dev/null +++ b/tests/assembly-llvm/pauth-init-fini.rs @@ -0,0 +1,29 @@ +// ignore-tidy-file-linelength +//@ add-minicore +//@ assembly-output: emit-asm +//@ revisions: ADDR_DISC NO_ADDR_DISC +//@ [ADDR_DISC] compile-flags: --target=aarch64-unknown-linux-pauthtest +//@ [ADDR_DISC] needs-llvm-components: aarch64 +//@ [NO_ADDR_DISC] compile-flags: --target=aarch64-unknown-linux-pauthtest -Zpointer-authentication=-init-fini-address-discrimination +//@ [NO_ADDR_DISC] needs-llvm-components: aarch64 + +// Init/fini entries are signed with the init/fini discriminator (55764). By default they are also +// address-discriminated, which LLVM emits as `addr` in the AUTH relocation: the loader blends in +// the address of the entry. +// `-init-fini-address-discrimination` turns that off. + +#![feature(no_core)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; + +extern "C" fn init_fn() {} + +// CHECK: .section .init_array.90 +// ADDR_DISC: .xword {{.*}}init_fn@AUTH(ia,55764,addr) +// NO_ADDR_DISC: .xword {{.*}}init_fn@AUTH(ia,55764){{$}} +#[used] +#[link_section = ".init_array.90"] +static GLOBAL_INIT: extern "C" fn() = init_fn; diff --git a/tests/codegen-llvm/pauth/pauth-attr-cli-flags.rs b/tests/codegen-llvm/pauth/pauth-attr-cli-flags.rs index 513850f1dd4db..876a997508f89 100644 --- a/tests/codegen-llvm/pauth/pauth-attr-cli-flags.rs +++ b/tests/codegen-llvm/pauth/pauth-attr-cli-flags.rs @@ -1,5 +1,5 @@ // ignore-tidy-file-linelength -//@ revisions: DEFAULT ALL DISABLE_JUMP DISABLE_AUTH_TRAPS DISABLE_CALLS DISABLE_INDIRCT_GOTOS DISABLE_RETURNS DISABLE_INTRINSICS DISABLE_TYPEINFO DISABLE_VT_PTR_ADDR DISABLE_VT_PTR_TYPE NONE +//@ revisions: DEFAULT ALL DISABLE_JUMP DISABLE_AUTH_TRAPS DISABLE_CALLS DISABLE_INDIRCT_GOTOS DISABLE_RETURNS DISABLE_INTRINSICS DISABLE_TYPEINFO DISABLE_VT_PTR_ADDR DISABLE_VT_PTR_TYPE DISABLE_INIT_FINI_ADDR DISABLE_INIT_FINI INIT_FINI_ADDR_ONLY NONE //@ add-minicore #![crate_type = "lib"] @@ -31,6 +31,12 @@ extern crate minicore; //@[DISABLE_VT_PTR_ADDR] compile-flags: --target=aarch64-unknown-linux-pauthtest -Zpointer-authentication=-vt-ptr-addr-discrimination //@[DISABLE_VT_PTR_TYPE] needs-llvm-components: aarch64 //@[DISABLE_VT_PTR_TYPE] compile-flags: --target=aarch64-unknown-linux-pauthtest -Zpointer-authentication=-vt-ptr-type-discrimination +//@[DISABLE_INIT_FINI_ADDR] needs-llvm-components: aarch64 +//@[DISABLE_INIT_FINI_ADDR] compile-flags: --target=aarch64-unknown-linux-pauthtest -Zpointer-authentication=-init-fini-address-discrimination +//@[DISABLE_INIT_FINI] needs-llvm-components: aarch64 +//@[DISABLE_INIT_FINI] compile-flags: --target=aarch64-unknown-linux-pauthtest -Zpointer-authentication=-init-fini +//@[INIT_FINI_ADDR_ONLY] needs-llvm-components: aarch64 +//@[INIT_FINI_ADDR_ONLY] compile-flags: --target=aarch64-unknown-linux-pauthtest -Zpointer-authentication=-init-fini,+init-fini-address-discrimination //@[NONE] needs-llvm-components: aarch64 //@[NONE] compile-flags: --target=aarch64-unknown-linux-pauthtest -Zpointer-authentication=-aarch64-jump-table-hardening,-auth-traps,-calls,-indirect-gotos,-return-addresses,-init-fini,-init-fini-address-discrimination,-intrinsics,-typeinfo-vt-ptr-discrimination,-vt-ptr-addr-discrimination,-vt-ptr-type-discrimination @@ -117,6 +123,17 @@ pub fn main() {} // DISABLE_VT_PTR_TYPE: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} // DISABLE_VT_PTR_TYPE-NEXT: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1759} +// Init/fini signing stays on; only its address discrimination bit (7) is cleared. +// DISABLE_INIT_FINI_ADDR: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// DISABLE_INIT_FINI_ADDR-NEXT: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1663} + +// As in Clang, the address discrimination bit (7) follows its own option: disabling init/fini +// signing clears only bit 6, and enabling address discrimination does not enable init/fini signing. +// DISABLE_INIT_FINI: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// DISABLE_INIT_FINI-NEXT: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1727} +// INIT_FINI_ADDR_ONLY: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// INIT_FINI_ADDR_ONLY-NEXT: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1727} + // NONE-NOT: ptrauth-returns // NONE-NOT: aarch64-jump-table-hardening // NONE-NOT: ptrauth-auth-traps diff --git a/tests/codegen-llvm/pauth/pauth-init-fini.rs b/tests/codegen-llvm/pauth/pauth-init-fini.rs index 5550100ae7f92..26895d070858d 100644 --- a/tests/codegen-llvm/pauth/pauth-init-fini.rs +++ b/tests/codegen-llvm/pauth/pauth-init-fini.rs @@ -1,6 +1,6 @@ // ignore-tidy-file-linelength //@ add-minicore -//@ revisions: O0_PAUTH O3_PAUTH O0_PAUTH-ADDR-DISC O3_PAUTH-ADDR-DISC O0_PAUTH-NO-INIT-FINI O3_PAUTH-NO-INIT-FINI +//@ revisions: O0_PAUTH O3_PAUTH O0_PAUTH-ADDR-DISC O3_PAUTH-ADDR-DISC O0_PAUTH-NO-INIT-FINI O3_PAUTH-NO-INIT-FINI O0_PAUTH-NO-ADDR-DISC O3_PAUTH-NO-ADDR-DISC O0_PAUTH-ADDR-DISC-ONLY //@ [O0_PAUTH] needs-llvm-components: aarch64 //@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 @@ -13,10 +13,20 @@ //@ [O3_PAUTH-ADDR-DISC] needs-llvm-components: aarch64 //@ [O3_PAUTH-ADDR-DISC] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 -Zpointer-authentication=+init-fini-address-discrimination //@ [O3_PAUTH-NO-INIT-FINI] needs-llvm-components: aarch64 -//@ [O3_PAUTH-NO-INIT-FINI] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 -Zpointer-authentication=-init-fini +//@ [O3_PAUTH-NO-INIT-FINI] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 -Zpointer-authentication=-init-fini +//@ [O0_PAUTH-NO-ADDR-DISC] needs-llvm-components: aarch64 +//@ [O0_PAUTH-NO-ADDR-DISC] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 -Zpointer-authentication=-init-fini-address-discrimination +//@ [O3_PAUTH-NO-ADDR-DISC] needs-llvm-components: aarch64 +//@ [O3_PAUTH-NO-ADDR-DISC] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 -Zpointer-authentication=-init-fini-address-discrimination +//@ [O0_PAUTH-ADDR-DISC-ONLY] needs-llvm-components: aarch64 +//@ [O0_PAUTH-ADDR-DISC-ONLY] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 -Zpointer-authentication=-init-fini,+init-fini-address-discrimination -// Make sure that init/fini metadata uses correct discriminator: 0xd9d4/55764 - ptrauth_string_discriminator("init_fini"). -// And that address discriminator can be enabled. +// Make sure that init/fini metadata uses correct discriminator: 0xd9d4/55764 - +// ptrauth_string_discriminator("init_fini"). Address discrimination is on by default, as in Clang: +// an entry carries the placeholder address discriminator `inttoptr (i64 1 to ptr)`, which LLVM +// emits as address diversity, so the loader blends in the address of the entry. +// With `-init-fini-address-discrimination`, an entry has no address discriminator, +// `+init-fini-address-discrimination` alone does not enable init/fini signing. #![feature(no_core, lang_items)] #![no_std] @@ -28,20 +38,26 @@ use minicore::*; // O0_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" // O3_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" -// O0_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr @_RNvCsf7kshQi9mOB_15pauth_init_fini7init_fn), section ".init_array.90" -// O3_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr @_RNvCsf7kshQi9mOB_15pauth_init_fini7init_fn), section ".init_array.90" +// O0_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" +// O3_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" // O0_PAUTH-NO-INIT-FINI-NOT: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth -// O0_PAUTH-NO-INIT-FINI-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth +// O3_PAUTH-NO-INIT-FINI-NOT: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth +// O0_PAUTH-ADDR-DISC-ONLY-NOT: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth +// O0_PAUTH-NO-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764), section ".init_array.90" +// O3_PAUTH-NO-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764), section ".init_array.90" #[used] #[link_section = ".init_array.90"] static GLOBAL_INIT: extern "C" fn() = init_fn; // O0_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" // O3_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" -// O0_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr @_RNvCsf7kshQi9mOB_15pauth_init_fini7fini_fn), section ".fini_array.90" -// O3_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr @_RNvCsf7kshQi9mOB_15pauth_init_fini7fini_fn), section ".fini_array.90" +// O0_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" +// O3_PAUTH-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" // O0_PAUTH-NO-INIT-FINI-NOT: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth // O3_PAUTH-NO-INIT-FINI-NOT: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth +// O0_PAUTH-ADDR-DISC-ONLY-NOT: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth +// O0_PAUTH-NO-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764), section ".fini_array.90" +// O3_PAUTH-NO-ADDR-DISC: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764), section ".fini_array.90" #[used] #[link_section = ".fini_array.90"] static GLOBAL_FINI: extern "C" fn(i32) = fini_fn; diff --git a/tests/ui/pointer_authentication/init-fini-unsigned-abi.rs b/tests/ui/pointer_authentication/init-fini-unsigned-abi.rs new file mode 100644 index 0000000000000..cad7bcaf13799 --- /dev/null +++ b/tests/ui/pointer_authentication/init-fini-unsigned-abi.rs @@ -0,0 +1,39 @@ +//@ add-minicore +//@ build-fail +//@ compile-flags: --target=aarch64-unknown-linux-pauthtest --crate-type=lib -Zcodegen-source-order +//@ needs-llvm-components: aarch64 +//@ ignore-backends: gcc + +// For pointer authentication the loader authenticates every entry of an init/fini array with the +// init/fini schema, but only functions whose ABI is supported (see `is_ptrauth_signed_fn`) can be +// signed. +// Reject non supported entries instead of emitting entries that fail authentication when the loader +// runs them. + +#![feature(no_core)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn rust_init() {} + +fn rust_fini() {} + +extern "C" fn c_init() {} + +#[used] +#[link_section = ".init_array"] +static RUST_INIT: fn() = rust_init; +//~^ ERROR `rust_init` is placed in `.init_array`, but pointer authentication does not sign its ABI + +#[used] +#[link_section = ".fini_array.100"] +static RUST_FINI: [fn(); 3] = [rust_init, rust_fini, rust_fini]; +//~^ ERROR `rust_init` is placed in `.fini_array.100` +//~| ERROR `rust_fini` is placed in `.fini_array.100` + +#[used] +#[link_section = ".init_array"] +static C_INIT: extern "C" fn() = c_init; diff --git a/tests/ui/pointer_authentication/init-fini-unsigned-abi.stderr b/tests/ui/pointer_authentication/init-fini-unsigned-abi.stderr new file mode 100644 index 0000000000000..4a28b6eba0c78 --- /dev/null +++ b/tests/ui/pointer_authentication/init-fini-unsigned-abi.stderr @@ -0,0 +1,29 @@ +error: `rust_init` is placed in `.init_array`, but pointer authentication does not sign its ABI + --> $DIR/init-fini-unsigned-abi.rs:28:1 + | +LL | static RUST_INIT: fn() = rust_init; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the loader authenticates every entry of `.init_array` and `.fini_array` with the init/fini signing schema, so an unsigned entry fails authentication when the loader runs it + = help: declare `rust_init` as `extern "C"` + +error: `rust_init` is placed in `.fini_array.100`, but pointer authentication does not sign its ABI + --> $DIR/init-fini-unsigned-abi.rs:33:1 + | +LL | static RUST_FINI: [fn(); 3] = [rust_init, rust_fini, rust_fini]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the loader authenticates every entry of `.init_array` and `.fini_array` with the init/fini signing schema, so an unsigned entry fails authentication when the loader runs it + = help: declare `rust_init` as `extern "C"` + +error: `rust_fini` is placed in `.fini_array.100`, but pointer authentication does not sign its ABI + --> $DIR/init-fini-unsigned-abi.rs:33:1 + | +LL | static RUST_FINI: [fn(); 3] = [rust_init, rust_fini, rust_fini]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the loader authenticates every entry of `.init_array` and `.fini_array` with the init/fini signing schema, so an unsigned entry fails authentication when the loader runs it + = help: declare `rust_fini` as `extern "C"` + +error: aborting due to 3 previous errors +