Skip to content

Commit a897742

Browse files
authored
Initial back-edge CFI implementation (#3606)
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 709716b commit a897742

File tree

17 files changed

+319
-43
lines changed

17 files changed

+319
-43
lines changed

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

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,45 @@ 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 using the A key are generated \
34+
and simple functions that do not use the stack are not affected \
35+
unless overridden by other settings.",
36+
"",
37+
false,
38+
);
39+
setting.add_bool(
40+
"sign_return_address_with_bkey",
41+
"Use the B key with pointer authentication instructions instead of \
42+
the default A key; does not have an effect on code generation by \
43+
itself. Some platform ABIs may require this, for example.",
44+
"",
45+
false,
46+
);
947

1048
setting.add_predicate("use_lse", predicate!(has_lse));
1149
setting.build()

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

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::ir::MemFlags;
77
use crate::ir::Opcode;
88
use crate::ir::{ExternalName, LibCall, Signature};
99
use crate::isa;
10-
use crate::isa::aarch64::{inst::EmitState, inst::*};
10+
use crate::isa::aarch64::{inst::EmitState, inst::*, settings as aarch64_settings};
1111
use crate::isa::unwind::UnwindInst;
1212
use crate::machinst::*;
1313
use crate::settings;
@@ -67,9 +67,13 @@ fn saved_reg_stack_size(
6767
/// point for the trait; it is never actually instantiated.
6868
pub(crate) struct AArch64MachineDeps;
6969

70+
impl IsaFlags for aarch64_settings::Flags {}
71+
7072
impl ABIMachineSpec for AArch64MachineDeps {
7173
type I = Inst;
7274

75+
type F = aarch64_settings::Flags;
76+
7377
fn word_bits() -> u32 {
7478
64
7579
}
@@ -377,8 +381,22 @@ impl ABIMachineSpec for AArch64MachineDeps {
377381
}
378382
}
379383

380-
fn gen_ret(rets: Vec<Reg>) -> Inst {
381-
Inst::Ret { rets }
384+
fn gen_ret(setup_frame: bool, isa_flags: &aarch64_settings::Flags, rets: Vec<Reg>) -> Inst {
385+
if isa_flags.sign_return_address() && (setup_frame || isa_flags.sign_return_address_all()) {
386+
let key = if isa_flags.sign_return_address_with_bkey() {
387+
APIKey::B
388+
} else {
389+
APIKey::A
390+
};
391+
392+
Inst::AuthenticatedRet {
393+
key,
394+
is_hint: !isa_flags.has_pauth(),
395+
rets,
396+
}
397+
} else {
398+
Inst::Ret { rets }
399+
}
382400
}
383401

384402
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallInstVec<Inst> {
@@ -493,19 +511,39 @@ impl ABIMachineSpec for AArch64MachineDeps {
493511
}
494512
}
495513

496-
fn gen_debug_frame_info(
514+
fn gen_prologue_start(
515+
setup_frame: bool,
497516
call_conv: isa::CallConv,
498517
flags: &settings::Flags,
499-
_isa_flags: &Vec<settings::Value>,
518+
isa_flags: &aarch64_settings::Flags,
500519
) -> SmallInstVec<Inst> {
501520
let mut insts = SmallVec::new();
502-
if flags.unwind_info() && call_conv.extends_apple_aarch64() {
521+
522+
if isa_flags.sign_return_address() && (setup_frame || isa_flags.sign_return_address_all()) {
523+
let key = if isa_flags.sign_return_address_with_bkey() {
524+
APIKey::B
525+
} else {
526+
APIKey::A
527+
};
528+
529+
insts.push(Inst::Pacisp { key });
530+
531+
if flags.unwind_info() {
532+
insts.push(Inst::Unwind {
533+
inst: UnwindInst::Aarch64SetPointerAuth {
534+
return_addresses: true,
535+
},
536+
});
537+
}
538+
} else if flags.unwind_info() && call_conv.extends_apple_aarch64() {
539+
// The macOS unwinder seems to require this.
503540
insts.push(Inst::Unwind {
504541
inst: UnwindInst::Aarch64SetPointerAuth {
505542
return_addresses: false,
506543
},
507544
});
508545
}
546+
509547
insts
510548
}
511549

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,16 @@
672672
(Ret
673673
(rets VecReg))
674674

675+
;; A machine return instruction with pointer authentication using SP as the
676+
;; modifier. This instruction requires pointer authentication support
677+
;; (FEAT_PAuth) unless `is_hint` is true, in which case it is equivalent to
678+
;; the combination of a no-op and a return instruction on platforms without
679+
;; the relevant support.
680+
(AuthenticatedRet
681+
(key APIKey)
682+
(is_hint bool)
683+
(rets VecReg))
684+
675685
;; An unconditional branch.
676686
(Jump
677687
(dest BranchTarget))
@@ -746,6 +756,12 @@
746756
(rd WritableReg)
747757
(mem AMode))
748758

759+
;; Pointer authentication code for instruction address with modifier in SP;
760+
;; equivalent to a no-op if Pointer authentication (FEAT_PAuth) is not
761+
;; supported.
762+
(Pacisp
763+
(key APIKey))
764+
749765
;; Marker, no-op in generated code: SP "virtual offset" is adjusted. This
750766
;; controls how AMode::NominalSPOffset args are lowered.
751767
(VirtualSPOffsetAdj
@@ -1308,6 +1324,13 @@
13081324
(Xchg)
13091325
))
13101326

1327+
;; Keys for instruction address PACs
1328+
(type APIKey
1329+
(enum
1330+
(A)
1331+
(B)
1332+
))
1333+
13111334
;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13121335
(decl use_lse () Inst)
13131336
(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
@@ -2774,6 +2774,19 @@ impl MachInstEmit for Inst {
27742774
&Inst::Ret { .. } => {
27752775
sink.put4(0xd65f03c0);
27762776
}
2777+
&Inst::AuthenticatedRet { key, is_hint, .. } => {
2778+
let key = match key {
2779+
APIKey::A => 0b0,
2780+
APIKey::B => 0b1,
2781+
};
2782+
2783+
if is_hint {
2784+
sink.put4(0xd50323bf | key << 6); // autiasp / autibsp
2785+
Inst::Ret { rets: vec![] }.emit(&[], sink, emit_info, state);
2786+
} else {
2787+
sink.put4(0xd65f0bff | key << 10); // retaa / retab
2788+
}
2789+
}
27772790
&Inst::Call { ref info } => {
27782791
if let Some(s) = state.take_stack_map() {
27792792
sink.add_stack_map(StackMapExtent::UpcomingBytes(4), s);
@@ -3064,6 +3077,14 @@ impl MachInstEmit for Inst {
30643077
add.emit(&[], sink, emit_info, state);
30653078
}
30663079
}
3080+
&Inst::Pacisp { key } => {
3081+
let key = match key {
3082+
APIKey::A => 0b0,
3083+
APIKey::B => 0b1,
3084+
};
3085+
3086+
sink.put4(0xd503233f | key << 6);
3087+
}
30673088
&Inst::VirtualSPOffsetAdj { offset } => {
30683089
trace!(
30693090
"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((Inst::Csdb, "9F2203D5", "csdb"));

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

Lines changed: 31 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.
@@ -982,6 +983,11 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
982983
collector.reg_use(ret);
983984
}
984985
}
986+
&Inst::AuthenticatedRet { ref rets, .. } => {
987+
for &ret in rets {
988+
collector.reg_use(ret);
989+
}
990+
}
985991
&Inst::Jump { .. } => {}
986992
&Inst::Call { ref info, .. } => {
987993
collector.reg_uses(&info.uses[..]);
@@ -1030,6 +1036,7 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
10301036
collector.reg_def(rd);
10311037
memarg_operands(mem, collector);
10321038
}
1039+
&Inst::Pacisp { .. } => {}
10331040
&Inst::VirtualSPOffsetAdj { .. } => {}
10341041

10351042
&Inst::ElfTlsGetAddr { .. } => {
@@ -1089,7 +1096,7 @@ impl MachInst for Inst {
10891096

10901097
fn is_term(&self) -> MachTerminator {
10911098
match self {
1092-
&Inst::Ret { .. } => MachTerminator::Ret,
1099+
&Inst::Ret { .. } | &Inst::AuthenticatedRet { .. } => MachTerminator::Ret,
10931100
&Inst::Jump { .. } => MachTerminator::Uncond,
10941101
&Inst::CondBr { .. } => MachTerminator::Cond,
10951102
&Inst::IndirectBr { .. } => MachTerminator::Indirect,
@@ -2476,6 +2483,18 @@ impl Inst {
24762483
format!("blr {}", rn)
24772484
}
24782485
&Inst::Ret { .. } => "ret".to_string(),
2486+
&Inst::AuthenticatedRet { key, is_hint, .. } => {
2487+
let key = match key {
2488+
APIKey::A => "a",
2489+
APIKey::B => "b",
2490+
};
2491+
2492+
if is_hint {
2493+
"auti".to_string() + key + "sp ; ret"
2494+
} else {
2495+
"reta".to_string() + key
2496+
}
2497+
}
24792498
&Inst::Jump { ref dest } => {
24802499
let dest = dest.pretty_print(0, allocs);
24812500
format!("b {}", dest)
@@ -2650,6 +2669,14 @@ impl Inst {
26502669
}
26512670
ret
26522671
}
2672+
&Inst::Pacisp { key } => {
2673+
let key = match key {
2674+
APIKey::A => "a",
2675+
APIKey::B => "b",
2676+
};
2677+
2678+
"paci".to_string() + key + "sp"
2679+
}
26532680
&Inst::VirtualSPOffsetAdj { offset } => {
26542681
state.virtual_sp_offset += offset;
26552682
format!("virtual_sp_offset_adjust {}", offset)

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::settings as shared_settings;
1414
use alloc::{boxed::Box, vec::Vec};
1515
use core::fmt;
1616
use regalloc2::MachineEnv;
17-
use target_lexicon::{Aarch64Architecture, Architecture, Triple};
17+
use target_lexicon::{Aarch64Architecture, Architecture, OperatingSystem, Triple};
1818

1919
// New backend:
2020
mod abi;
@@ -59,7 +59,7 @@ impl AArch64Backend {
5959
flags: shared_settings::Flags,
6060
) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
6161
let emit_info = EmitInfo::new(flags.clone());
62-
let abi = Box::new(abi::AArch64ABICallee::new(func, self)?);
62+
let abi = Box::new(abi::AArch64ABICallee::new(func, self, &self.isa_flags)?);
6363
compile::compile::<AArch64Backend>(func, self, abi, &self.machine_env, emit_info)
6464
}
6565
}
@@ -147,6 +147,21 @@ impl TargetIsa for AArch64Backend {
147147

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

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ use crate::ir::MemFlags;
7373
use crate::ir::Signature;
7474
use crate::ir::Type;
7575
use crate::isa;
76-
use crate::isa::s390x::inst::*;
76+
use crate::isa::s390x::{inst::*, settings as s390x_settings};
7777
use crate::isa::unwind::UnwindInst;
7878
use crate::machinst::*;
7979
use crate::machinst::{RealReg, Reg, RegClass, Writable};
@@ -206,9 +206,13 @@ impl Into<MemArg> for StackAMode {
206206
/// point for the trait; it is never actually instantiated.
207207
pub struct S390xMachineDeps;
208208

209+
impl IsaFlags for s390x_settings::Flags {}
210+
209211
impl ABIMachineSpec for S390xMachineDeps {
210212
type I = Inst;
211213

214+
type F = s390x_settings::Flags;
215+
212216
fn word_bits() -> u32 {
213217
64
214218
}
@@ -391,7 +395,7 @@ impl ABIMachineSpec for S390xMachineDeps {
391395
}
392396
}
393397

394-
fn gen_ret(rets: Vec<Reg>) -> Inst {
398+
fn gen_ret(_setup_frame: bool, _isa_flags: &s390x_settings::Flags, rets: Vec<Reg>) -> Inst {
395399
Inst::Ret {
396400
link: gpr(14),
397401
rets,

0 commit comments

Comments
 (0)