Skip to content

Commit 1939f1b

Browse files
committed
Add support for init/fini signing and correctly sign extern weak globals
Also add flag for ELF-GOT signing.
1 parent a9c8a37 commit 1939f1b

4 files changed

Lines changed: 129 additions & 6 deletions

File tree

compiler/rustc_codegen_llvm/src/consts.rs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
4949
//
5050
// Statics have a guaranteed meaningful address so it's less clear that we want to do
5151
// something like this; it's also harder.
52-
if !is_static {
52+
if matches!(is_static, IsStatic::No) {
5353
assert!(alloc.len() != 0);
5454
}
5555
let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1);
@@ -120,14 +120,28 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
120120
as u64;
121121

122122
let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx);
123-
124-
llvals.push(cx.scalar_to_backend(
123+
// Pauthtest function pointers stored in init/fini arrays need special handling.
124+
let pac_metadata = Some(
125+
if cx.sess().target.env == Env::Pauthtest && matches!(is_init_fini, IsInitOrFini::Yes) {
126+
PacMetadata {
127+
// Must correspond to ptrauth_key_init_fini_pointer from `ptrauth.h`.
128+
key: 0,
129+
// ptrauth_string_discriminator("init_fini")
130+
disc: 0xd9d4,
131+
addr_diversity: AddressDiversity::Synthetic(1),
132+
}
133+
} else {
134+
PacMetadata::default()
135+
},
136+
);
137+
llvals.push(cx.scalar_to_backend_with_pac(
125138
InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx),
126139
Scalar::Initialized {
127140
value: Primitive::Pointer(address_space),
128141
valid_range: WrappingRange::full(pointer_size),
129142
},
130143
cx.type_ptr_ext(address_space),
144+
pac_metadata,
131145
));
132146
next_offset = offset + pointer_size_bytes;
133147
}
@@ -152,7 +166,19 @@ fn codegen_static_initializer<'ll, 'tcx>(
152166
def_id: DefId,
153167
) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
154168
let alloc = cx.tcx.eval_static_initializer(def_id)?;
155-
Ok((const_alloc_to_llvm(cx, alloc.inner(), /*static*/ true), alloc))
169+
let attrs = cx.tcx.codegen_fn_attrs(def_id);
170+
let is_in_init_fini: IsInitOrFini = attrs
171+
.link_section
172+
.map(|link_section| {
173+
let s = link_section.as_str();
174+
if s.starts_with(".init_array") || s.starts_with(".fini_array") {
175+
IsInitOrFini::Yes
176+
} else {
177+
IsInitOrFini::No
178+
}
179+
})
180+
.unwrap_or(IsInitOrFini::No);
181+
Ok((const_alloc_to_llvm(cx, alloc.inner(), IsStatic::Yes, is_in_init_fini), alloc))
156182
}
157183

158184
fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) {
@@ -175,6 +201,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
175201
if let Some(linkage) = attrs.import_linkage {
176202
debug!("get_static: sym={} linkage={:?}", sym, linkage);
177203

204+
let mut should_sign = false;
178205
// Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare
179206
// an extern_weak function, otherwise a global with the desired linkage.
180207
let g1 = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) {
@@ -187,8 +214,13 @@ fn check_and_apply_linkage<'ll, 'tcx>(
187214
&& let ty::FnPtr(sig, header) = args.type_at(0).kind()
188215
{
189216
let fn_sig = sig.with(*header);
190-
191217
let fn_abi = cx.fn_abi_of_fn_ptr(fn_sig, ty::List::empty());
218+
// Decide if the initializer needs to be signed
219+
if cx.sess().target.env == Env::Pauthtest
220+
&& matches!(fn_sig.abi(), ExternAbi::C { .. })
221+
{
222+
should_sign = true;
223+
}
192224
cx.declare_fn(sym, &fn_abi, None)
193225
} else {
194226
cx.declare_global(sym, cx.type_i8())
@@ -217,7 +249,24 @@ fn check_and_apply_linkage<'ll, 'tcx>(
217249
})
218250
});
219251
llvm::set_linkage(g2, llvm::Linkage::InternalLinkage);
220-
llvm::set_initializer(g2, g1);
252+
253+
// Sign the function pointer that is used to initialize the global
254+
let initializer = if should_sign {
255+
let key: u32 = 0;
256+
let discriminator: u64 = 0;
257+
258+
const_ptr_auth(
259+
cx.const_bitcast(g1, llty),
260+
key,
261+
discriminator,
262+
None, /* address_diversity */
263+
)
264+
} else {
265+
g1
266+
};
267+
268+
llvm::set_initializer(g2, initializer);
269+
221270
g2
222271
} else if cx.tcx.sess.target.arch == Arch::X86
223272
&& common::is_mingw_gnu_toolchain(&cx.tcx.sess.target)

compiler/rustc_session/src/options.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2568,6 +2568,7 @@ options! {
25682568
(default: no)"),
25692569
patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED],
25702570
"nop padding at function entry"),
2571+
pauth_enable_elf_got: bool = (false, parse_bool, [TRACKED], "enable signing of ELF GOT entries"),
25712572
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
25722573
"whether to use the PLT when calling into shared libraries;
25732574
only has effect for PIC code on systems with ELF binaries
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// ignore-tidy-linelength
2+
//@ only-aarch64-unknown-linux-pauthtest
3+
//@ revisions: O0_PAUTH O3_PAUTH O0_NO_PAUTH O3_NO_PAUTH
4+
5+
//@ [O0_PAUTH] needs-llvm-components: aarch64
6+
//@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0
7+
//@ [O3_PAUTH] needs-llvm-components: aarch64
8+
//@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3
9+
//@ [O0_NO_PAUTH] needs-llvm-components: aarch64
10+
//@ [O0_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=0
11+
//@ [O3_NO_PAUTH] needs-llvm-components: aarch64
12+
//@ [O3_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=3
13+
14+
#![crate_type = "lib"]
15+
#![feature(linkage)]
16+
17+
// O0_PAUTH: @{{[0-9A-Za-z_]+}}FUNCTION_PTR_DECL = constant ptr ptrauth (ptr @copy_file_range, i32 0)
18+
// O0_PAUTH: declare i64 @copy_file_range({{.*}})
19+
// O3_PAUTH: @{{[0-9A-Za-z_]+}}FUNCTION_PTR_DECL = constant ptr ptrauth (ptr @copy_file_range, i32 0)
20+
// O3_PAUTH: declare {{.*}} i64 @copy_file_range({{.*}})
21+
//
22+
// O0_NO_PAUTH-NOT: ptr ptrauth
23+
// O3_NO_PAUTH-NOT: ptr ptrauth
24+
extern "C" {
25+
#[link_name = "copy_file_range"]
26+
#[linkage = "extern_weak"]
27+
fn copy_file_range(
28+
fd_in: i32,
29+
off_in: *mut i64,
30+
fd_out: i32,
31+
off_out: *mut i64,
32+
len: i64,
33+
flags: i32,
34+
) -> i64;
35+
}
36+
37+
#[used]
38+
static FUNCTION_PTR_DECL: unsafe extern "C" fn(i32, *mut i64, i32, *mut i64, i64, i32) -> i64 =
39+
copy_file_range;
40+
41+
// O0_PAUTH: !{{[0-9]+}} = !{i32 7, !"ptrauth-sign-personality", i32 1}
42+
// O3_PAUTH: !{{[0-9]+}} = !{i32 7, !"ptrauth-sign-personality", i32 1}
43+
44+
// O0_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 7, !"ptrauth-sign-personality", i32 1}
45+
// O3_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 7, !"ptrauth-sign-personality", i32 1}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// ignore-tidy-linelength
2+
//@ only-aarch64-unknown-linux-pauthtest
3+
//@ revisions: O0_PAUTH O3_PAUTH
4+
5+
//@ [O0_PAUTH] needs-llvm-components: aarch64
6+
//@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0
7+
//@ [O3_PAUTH] needs-llvm-components: aarch64
8+
//@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3
9+
10+
// Make sure that init/fini metadata uses correct discriminator: 0xd9d4/55764
11+
12+
#![crate_type = "lib"]
13+
#![feature(linkage)]
14+
15+
// 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"
16+
// 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"
17+
#[used]
18+
#[link_section = ".init_array.90"]
19+
static GLOBAL_INIT: extern "C" fn() = init_fn;
20+
21+
// 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"
22+
// 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"
23+
#[used]
24+
#[link_section = ".fini_array.90"]
25+
static GLOBAL_FINI: extern "C" fn(i32) = fini_fn;
26+
27+
extern "C" fn init_fn() {}
28+
extern "C" fn fini_fn(_: i32) {}

0 commit comments

Comments
 (0)