Skip to content

Commit 158e0aa

Browse files
committed
Initial back-edge CFI implementation
Give the user the option to sign and to authenticate function return addresses with the operations introduced by the Pointer Authentication extension to the Arm instruction set architecture. Copyright (c) 2021, Arm Limited.
1 parent 445cc87 commit 158e0aa

File tree

13 files changed

+267
-20
lines changed

13 files changed

+267
-20
lines changed

cranelift/codegen/meta/src/isa/arm64.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,44 @@ use crate::shared::Definitions as SharedDefinitions;
55

66
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
77
let mut setting = SettingGroupBuilder::new("arm64");
8-
let has_lse = setting.add_bool("has_lse", "Has Large System Extensions support.", "", false);
8+
let has_lse = setting.add_bool(
9+
"has_lse",
10+
"Has Large System Extensions (FEAT_LSE) support.",
11+
"",
12+
false,
13+
);
14+
15+
setting.add_bool(
16+
"has_pauth",
17+
"Has Pointer authentication (FEAT_PAuth) support; enables the use of \
18+
non-HINT instructions, but does not have an effect on code generation \
19+
by itself.",
20+
"",
21+
false,
22+
);
23+
setting.add_bool(
24+
"sign_return_address_all",
25+
"If function return address signing is enabled, then apply it to all \
26+
functions; does not have an effect on code generation by itself.",
27+
"",
28+
false,
29+
);
30+
setting.add_bool(
31+
"sign_return_address",
32+
"Use pointer authentication instructions to sign function return \
33+
addresses; HINT-space instructions are generated and simple functions \
34+
that do not use the stack are not affected unless overridden by other \
35+
settings.",
36+
"",
37+
false,
38+
);
39+
setting.add_bool(
40+
"sign_return_address_with_bkey",
41+
"Use the B key with pointer authentication instructions; does not have \
42+
an effect on code generation by itself.",
43+
"",
44+
false,
45+
);
946

1047
setting.add_predicate("use_lse", predicate!(has_lse));
1148
setting.build()

cranelift/codegen/src/isa/aarch64/abi.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -503,8 +503,24 @@ impl ABIMachineSpec for AArch64MachineDeps {
503503
}
504504
}
505505

506-
fn gen_ret(rets: Vec<Reg>) -> Inst {
507-
Inst::Ret { rets }
506+
fn gen_ret(setup_frame: bool, isa_flags: &Vec<settings::Value>, rets: Vec<Reg>) -> Inst {
507+
if has_bool_setting("sign_return_address", isa_flags)
508+
&& (setup_frame || has_bool_setting("sign_return_address_all", isa_flags))
509+
{
510+
let key = if has_bool_setting("sign_return_address_with_bkey", isa_flags) {
511+
APIKey::B
512+
} else {
513+
APIKey::A
514+
};
515+
516+
Inst::AuthenticatedRet {
517+
key,
518+
is_hint: !has_bool_setting("has_pauth", isa_flags),
519+
rets,
520+
}
521+
} else {
522+
Inst::Ret { rets }
523+
}
508524
}
509525

510526
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallInstVec<Inst> {
@@ -622,19 +638,41 @@ impl ABIMachineSpec for AArch64MachineDeps {
622638
}
623639
}
624640

625-
fn gen_debug_frame_info(
641+
fn gen_prologue_start(
642+
setup_frame: bool,
626643
call_conv: isa::CallConv,
627644
flags: &settings::Flags,
628-
_isa_flags: &Vec<settings::Value>,
645+
isa_flags: &Vec<settings::Value>,
629646
) -> SmallInstVec<Inst> {
630647
let mut insts = SmallVec::new();
631-
if flags.unwind_info() && call_conv.extends_apple_aarch64() {
648+
649+
if has_bool_setting("sign_return_address", isa_flags)
650+
&& (setup_frame || has_bool_setting("sign_return_address_all", isa_flags))
651+
{
652+
let key = if has_bool_setting("sign_return_address_with_bkey", isa_flags) {
653+
APIKey::B
654+
} else {
655+
APIKey::A
656+
};
657+
658+
insts.push(Inst::Pacisp { key });
659+
660+
if flags.unwind_info() {
661+
insts.push(Inst::Unwind {
662+
inst: UnwindInst::Aarch64SetPointerAuth {
663+
return_addresses: true,
664+
},
665+
});
666+
}
667+
} else if flags.unwind_info() && call_conv.extends_apple_aarch64() {
668+
// The macOS unwinder seems to require this.
632669
insts.push(Inst::Unwind {
633670
inst: UnwindInst::Aarch64SetPointerAuth {
634671
return_addresses: false,
635672
},
636673
});
637674
}
675+
638676
insts
639677
}
640678

@@ -1334,3 +1372,10 @@ fn is_reg_clobbered_by_call(call_conv_of_callee: isa::CallConv, r: RealReg) -> b
13341372
}
13351373
}
13361374
}
1375+
1376+
fn has_bool_setting(name: &str, isa_flags: &Vec<settings::Value>) -> bool {
1377+
isa_flags
1378+
.iter()
1379+
.find(|&f| f.name == name)
1380+
.map_or(false, |f| f.as_bool().unwrap_or(false))
1381+
}

cranelift/codegen/src/isa/aarch64/inst.isle

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,16 @@
654654
(Ret
655655
(rets VecReg))
656656

657+
;; A machine return instruction with pointer authentication using SP as the
658+
;; modifier. This instruction requires pointer authentication support
659+
;; (FEAT_PAuth) unless `is_hint` is true, in which case it is equivalent to
660+
;; the combination of a no-op and a return instruction on platforms without
661+
;; the relevant support.
662+
(AuthenticatedRet
663+
(key APIKey)
664+
(is_hint bool)
665+
(rets VecReg))
666+
657667
;; A placeholder instruction, generating no code, meaning that a function epilogue must be
658668
;; inserted there.
659669
(EpiloguePlaceholder)
@@ -733,6 +743,12 @@
733743
(rd WritableReg)
734744
(mem AMode))
735745

746+
;; Pointer authentication code for instruction address with modifier in SP;
747+
;; equivalent to a no-op if Pointer authentication (FEAT_PAuth) is not
748+
;; supported.
749+
(Pacisp
750+
(key APIKey))
751+
736752
;; Marker, no-op in generated code: SP "virtual offset" is adjusted. This
737753
;; controls how AMode::NominalSPOffset args are lowered.
738754
(VirtualSPOffsetAdj
@@ -1283,6 +1299,13 @@
12831299
(Xchg)
12841300
))
12851301

1302+
;; Keys for instruction address PACs
1303+
(type APIKey
1304+
(enum
1305+
(A)
1306+
(B)
1307+
))
1308+
12861309
;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12871310
(decl use_lse () Inst)
12881311
(extern extractor use_lse use_lse)

cranelift/codegen/src/isa/aarch64/inst/emit.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2756,6 +2756,19 @@ impl MachInstEmit for Inst {
27562756
&Inst::Ret { .. } => {
27572757
sink.put4(0xd65f03c0);
27582758
}
2759+
&Inst::AuthenticatedRet { key, is_hint, .. } => {
2760+
let key = match key {
2761+
APIKey::A => 0b0,
2762+
APIKey::B => 0b1,
2763+
};
2764+
2765+
if is_hint {
2766+
sink.put4(0xd50323bf | key << 6);
2767+
Inst::Ret { rets: vec![] }.emit(&[], sink, emit_info, state);
2768+
} else {
2769+
sink.put4(0xd65f0bff | key << 10);
2770+
}
2771+
}
27592772
&Inst::EpiloguePlaceholder => {
27602773
// Noop; this is just a placeholder for epilogues.
27612774
}
@@ -3059,6 +3072,14 @@ impl MachInstEmit for Inst {
30593072
add.emit(&[], sink, emit_info, state);
30603073
}
30613074
}
3075+
&Inst::Pacisp { key } => {
3076+
let key = match key {
3077+
APIKey::A => 0b0,
3078+
APIKey::B => 0b1,
3079+
};
3080+
3081+
sink.put4(0xd503233f | key << 6);
3082+
}
30623083
&Inst::VirtualSPOffsetAdj { offset } => {
30633084
log::trace!(
30643085
"virtual sp offset adjusted by {} -> {}",

cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ fn test_aarch64_binemit() {
3838
//
3939
// $ echo "mov x1, x2" | aarch64inst.sh
4040
insns.push((Inst::Ret { rets: vec![] }, "C0035FD6", "ret"));
41+
insns.push((
42+
Inst::AuthenticatedRet {
43+
key: APIKey::A,
44+
is_hint: true,
45+
rets: vec![],
46+
},
47+
"BF2303D5C0035FD6",
48+
"autiasp ; ret",
49+
));
50+
insns.push((
51+
Inst::AuthenticatedRet {
52+
key: APIKey::B,
53+
is_hint: false,
54+
rets: vec![],
55+
},
56+
"FF0F5FD6",
57+
"retab",
58+
));
59+
insns.push((Inst::Pacisp { key: APIKey::B }, "7F2303D5", "pacibsp"));
4160
insns.push((Inst::Nop0, "", "nop-zero-len"));
4261
insns.push((Inst::Nop4, "1F2003D5", "nop"));
4362
insns.push((

cranelift/codegen/src/isa/aarch64/inst/mod.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ mod emit_tests;
3636
// Instructions (top level): definition
3737

3838
pub use crate::isa::aarch64::lower::isle::generated_code::{
39-
ALUOp, ALUOp3, AtomicRMWLoopOp, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode,
40-
FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2,
41-
VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
39+
ALUOp, ALUOp3, APIKey, AtomicRMWLoopOp, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3,
40+
FpuRoundMode, FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp,
41+
VecLanesOp, VecMisc2, VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp,
42+
VecShiftImmOp,
4243
};
4344

4445
/// A floating-point unit (FPU) operation with two args, a register and an immediate.
@@ -979,6 +980,11 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
979980
collector.reg_use(ret);
980981
}
981982
}
983+
&Inst::AuthenticatedRet { ref rets, .. } => {
984+
for &ret in rets {
985+
collector.reg_use(ret);
986+
}
987+
}
982988
&Inst::Jump { .. } | &Inst::EpiloguePlaceholder => {}
983989
&Inst::Call { ref info, .. } => {
984990
collector.reg_uses(&info.uses[..]);
@@ -1025,6 +1031,7 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
10251031
collector.reg_def(rd);
10261032
memarg_operands(mem, collector);
10271033
}
1034+
&Inst::Pacisp { .. } => {}
10281035
&Inst::VirtualSPOffsetAdj { .. } => {}
10291036

10301037
&Inst::ElfTlsGetAddr { .. } => {
@@ -1091,7 +1098,9 @@ impl MachInst for Inst {
10911098

10921099
fn is_term(&self) -> MachTerminator {
10931100
match self {
1094-
&Inst::Ret { .. } | &Inst::EpiloguePlaceholder => MachTerminator::Ret,
1101+
&Inst::Ret { .. } | &Inst::AuthenticatedRet { .. } | &Inst::EpiloguePlaceholder => {
1102+
MachTerminator::Ret
1103+
}
10951104
&Inst::Jump { .. } => MachTerminator::Uncond,
10961105
&Inst::CondBr { .. } => MachTerminator::Cond,
10971106
&Inst::IndirectBr { .. } => MachTerminator::Indirect,
@@ -2532,6 +2541,18 @@ impl Inst {
25322541
format!("blr {}", rn)
25332542
}
25342543
&Inst::Ret { .. } => "ret".to_string(),
2544+
&Inst::AuthenticatedRet { key, is_hint, .. } => {
2545+
let key = match key {
2546+
APIKey::A => "a",
2547+
APIKey::B => "b",
2548+
};
2549+
2550+
if is_hint {
2551+
"auti".to_string() + key + "sp ; ret"
2552+
} else {
2553+
"reta".to_string() + key
2554+
}
2555+
}
25352556
&Inst::EpiloguePlaceholder => "epilogue placeholder".to_string(),
25362557
&Inst::Jump { ref dest } => {
25372558
let dest = dest.pretty_print(0, allocs);
@@ -2712,6 +2733,14 @@ impl Inst {
27122733
}
27132734
ret
27142735
}
2736+
&Inst::Pacisp { key } => {
2737+
let key = match key {
2738+
APIKey::A => "a",
2739+
APIKey::B => "b",
2740+
};
2741+
2742+
"paci".to_string() + key + "sp"
2743+
}
27152744
&Inst::VirtualSPOffsetAdj { offset } => {
27162745
state.virtual_sp_offset += offset;
27172746
format!("virtual_sp_offset_adjust {}", offset)

cranelift/codegen/src/isa/aarch64/mod.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::settings as shared_settings;
1212
use alloc::{boxed::Box, vec::Vec};
1313
use core::fmt;
1414
use regalloc2::MachineEnv;
15-
use target_lexicon::{Aarch64Architecture, Architecture, Triple};
15+
use target_lexicon::{Aarch64Architecture, Architecture, OperatingSystem, Triple};
1616

1717
// New backend:
1818
mod abi;
@@ -144,6 +144,21 @@ impl TargetIsa for AArch64Backend {
144144

145145
#[cfg(feature = "unwind")]
146146
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
147+
let is_apple_os = match self.triple.operating_system {
148+
OperatingSystem::Darwin
149+
| OperatingSystem::Ios
150+
| OperatingSystem::MacOSX { .. }
151+
| OperatingSystem::Tvos => true,
152+
_ => false,
153+
};
154+
155+
if self.isa_flags.sign_return_address()
156+
&& self.isa_flags.sign_return_address_with_bkey()
157+
&& !is_apple_os
158+
{
159+
unimplemented!("Specifying that the B key is used with pointer authentication instructions in the CIE is not implemented.");
160+
}
161+
147162
Some(inst::unwind::systemv::create_cie())
148163
}
149164

cranelift/codegen/src/isa/s390x/abi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ impl ABIMachineSpec for S390xMachineDeps {
342342
}
343343
}
344344

345-
fn gen_ret(rets: Vec<Reg>) -> Inst {
345+
fn gen_ret(_setup_frame: bool, _isa_flags: &Vec<settings::Value>, rets: Vec<Reg>) -> Inst {
346346
Inst::Ret {
347347
link: gpr(14),
348348
rets,

cranelift/codegen/src/isa/x64/abi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
357357
}
358358
}
359359

360-
fn gen_ret(rets: Vec<Reg>) -> Self::I {
360+
fn gen_ret(_setup_frame: bool, _isa_flags: &Vec<settings::Value>, rets: Vec<Reg>) -> Self::I {
361361
Inst::ret(rets)
362362
}
363363

0 commit comments

Comments
 (0)