我已经按照 AAPCS64 调用约定编写了一些 arm64 汇编代码。
现在我想将此代码集成到启用 PAC 和 BTI 的 C/C++ 项目中。 当链接器告诉我我缺少
GNU_PROPERTY_AARCH64_FEATURE_1_BTI
属性时,我第一次注意到麻烦:
ld: error: md5block_arm64.o: -z bti-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property
虽然设置此属性很简单,但我知道我可能需要更改部分代码以使它们了解 PAC/BTI。 为此需要进行哪些改变? 我对可以用作调整任何代码的指南的一般答案感兴趣,因此在这个问题中缺乏要调整的代码。
BTI 非常简单,并且不依赖于软件 ABI(除了首先启用 BTI 之外)。在
手册的当前版本(
K.a
)中,该行为记录在“D8.4.5.3 PSTATE.BTYPE”部分中。本质上:
前向边缘分支指令分为两类:
br
、braa
、braaz
、brab
和 brabz
blr
、blraa
、blraaz
、blrab
、blrabz
我将使用
br
和 blr
作为这些类别的简写。
新增了三个指令:
bti c
、bti j
和bti jc
。
blr
分支必须落在 bti c
或 bti jc
指令上。
br
和
x16
以外的寄存器作为目标地址的 x17
分支必须落在 bti j
或 bti jc
指令上。
br
或
x16
作为目标地址的 x17
分支可以落在任何 bti
指令上。
paciasp
和pacibsp
根据相关翻译机制的bti c
中的一些位充当bti jc
或SCTLR_ELn
- 只需假设bti c
是安全的。
所以为了兼容BTI代码,你必须:
paciasp
、pacibsp
或 bti c
。br
调用实际函数的)都使用 x16
或 x17
。bti j
添加到 switch 式 br
s 的所有可能目标。PAC 是一个完全不同的野兽。这取决于堆栈中所有的确切 ABI -
gnu
与 musl
、C 与 C++、头文件中的 __attribute__
说明符,...
AAPCS64 规范根本没有定义指针身份验证 ABI。 PAUTHELF64 对于如何以 ELF 文件格式进行编码有一些定义,但最重要的是它没有定义如何选择。
基本上任何代码指针合成、任何间接分支,甚至可能的内存加载都可能需要 PAC 指令 - 完全由实现定义。
现在,你很幸运,
-mbranch-protection=standard
似乎几乎不使用 PAC。来自标志的文档:
-mbranch-protection=none|standard|pac-ret[+leaf+b-key]|bti
选择要使用的分支保护功能。
是默认值,关闭所有类型的分支保护。none
打开所有类型的分支保护功能。如果某个功能有其他调整选项,则standard
将其设置为标准级别。standard
将返回地址签名打开到标准级别:使用 a-key 签名将返回地址保存到内存的函数(非叶函数实际上总是这样做)。可选参数pac-ret[+leaf]
可用于扩展签名以包含叶函数。可选参数leaf
可用于使用 B-key 而不是 A-key 对函数进行签名。b-key
开启分支目标识别机制。bti
基本上这只是使用PAC来保护堆栈帧,完全不影响不同编译单元之间的ABI。如果您想维护该选项的安全属性,那么所有溢出
x30
的函数都需要在溢出之前有一个 paciasp
以及在重新加载和 autiasp
之间有一个 ret
。 (如果您的代码不需要在没有 PAC 支持的硬件上运行,您可以将 autiasp
+ret
组合成单个 retaa
)。