-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[BOLT][AArch64] Do not crash on authenticated branch instructions #129898
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BOLT][AArch64] Do not crash on authenticated branch instructions #129898
Conversation
When an indirect branch instruction is decoded, analyzeIndirectBranch method is asked if this is a well-known code pattern. On AArch64, the only special pattern which is detected is Jump Table, emitted as a branch to the sum of a constant base address and a variable offset. Therefore, `Inst.getOpcode()` being one of `AArch64::BRA*` means Inst cannot belong to such Jump Table pattern, thus returning early.
@llvm/pr-subscribers-bolt Author: Anatoly Trosinenko (atrosinenko) ChangesWhen an indirect branch instruction is decoded, analyzeIndirectBranch method is asked if this is a well-known code pattern. On AArch64, the only special pattern which is detected is Jump Table, emitted as a branch to the sum of a constant base address and a variable offset. Therefore, Full diff: https://github.com/llvm/llvm-project/pull/129898.diff 2 Files Affected:
diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 685b2279e5afb..e073b197e70d2 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -547,6 +547,13 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
return false;
}
+ bool isBRA(const MCInst &Inst) const {
+ return (Inst.getOpcode() == AArch64::BRAA ||
+ Inst.getOpcode() == AArch64::BRAB ||
+ Inst.getOpcode() == AArch64::BRAAZ ||
+ Inst.getOpcode() == AArch64::BRABZ);
+ }
+
bool mayLoad(const MCInst &Inst) const override {
return isLDRB(Inst) || isLDRH(Inst) || isLDRW(Inst) || isLDRX(Inst) ||
isLDRQ(Inst) || isLDRD(Inst) || isLDRS(Inst);
@@ -941,6 +948,11 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
DenseMap<const MCInst *, SmallVector<MCInst *, 4>> &UDChain,
const MCExpr *&JumpTable, int64_t &Offset, int64_t &ScaleValue,
MCInst *&PCRelBase) const {
+ // The only kind of indirect branches we match is jump table, thus ignore
+ // authenticating branch instructions early.
+ if (isBRA(Inst))
+ return false;
+
// Expect AArch64 BR
assert(Inst.getOpcode() == AArch64::BR && "Unexpected opcode");
diff --git a/bolt/test/AArch64/test-indirect-branch.s b/bolt/test/AArch64/test-indirect-branch.s
index 1e16e76b11530..b99737ee97acc 100644
--- a/bolt/test/AArch64/test-indirect-branch.s
+++ b/bolt/test/AArch64/test-indirect-branch.s
@@ -5,7 +5,7 @@
// REQUIRES: system-linux, asserts
-// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown -mattr=+pauth %s -o %t.o
// RUN: %clang %cflags --target=aarch64-unknown-linux %t.o -o %t.exe -Wl,-q
// RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg --strict --debug-only=mcplus \
// RUN: -v=1 2>&1 | FileCheck %s
@@ -73,6 +73,27 @@ test2_0:
test2_1:
ret
+// Make sure BOLT does not crash trying to disassemble BRA* instructions.
+ .globl test_braa
+ .type test_braa, %function
+test_braa:
+ braa x0, x1
+
+ .globl test_brab
+ .type test_brab, %function
+test_brab:
+ brab x0, x1
+
+ .globl test_braaz
+ .type test_braaz, %function
+test_braaz:
+ braaz x0
+
+ .globl test_brabz
+ .type test_brabz, %function
+test_brabz:
+ brabz x0
+
.section .rodata,"a",@progbits
datatable:
.word test1_0-datatable
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM Thanks
folks how about to use isIndirectBranchOpcode func from AArch64InstrInfo.h file? |
One more point from my side, jump tables for aarch64 can be implemented over br & blr instructions. We should also include the checking for indirect call instructions |
@yavtuk Do you suggest replacing static inline bool isIndirectBranchOpcode(int Opc) {
switch (Opc) {
case AArch64::BR:
case AArch64::BRAA:
case AArch64::BRAB:
case AArch64::BRAAZ:
case AArch64::BRABZ:
return true;
}
return false;
} That is, Though, I agree that there may exist some redundancy in bool mayLoad(const MCInst &Inst) const override {
return isLDRB(Inst) || isLDRH(Inst) || isLDRW(Inst) || isLDRX(Inst) ||
isLDRQ(Inst) || isLDRD(Inst) || isLDRS(Inst);
} TableGen-erated descriptions from AArch64 backend could probably be re-used instead in |
@yavtuk Could you clarify this? If I understand the existing |
as example I think we can create the different function isIndirectAuthBranch or we can use if (isIndirectBranchOpcode() & !Inst.getOpcode() != AArch64::BR) If we can avoid duplication then let try to do it, if not you can leave it as is |
Current implementation for aarch64 supports only BR as indirect instruction for Jump tables, but I am working on the jump tables functionality right now, and I see a lot of JT with BLR instruction. If you are going to use BLRAA or other instructions it's worth to add checking for them as well |
Now got it, thank you! I thought these were the same four
Testing for assert(Inst.getOpcode() == AArch64::BR && "Unexpected opcode"); with if (Inst.getOpcode() != AArch64::BR)
return; This could make sense as "there are many variants of |
@atrosinenko the simplified version with array of functions pointers, clang -fjump-tables
objdump --disassemble=handleOptionJumpTable --no-addresses --no-show-raw-insn ./jt
|
looks like a natural way to express const int result = jumpTable[option]();
printf("result %d\n", result); in machine code, as |
I assume all the discussions on this PR are resolved now. @yavtuk I will merge this if you don't mind? |
Yes, you can, thanks |
When an indirect branch instruction is decoded, analyzeIndirectBranch method is asked if this is a well-known code pattern. On AArch64, the only special pattern which is detected is Jump Table, emitted as a branch to the sum of a constant base address and a variable offset. Therefore,
Inst.getOpcode()
being one ofAArch64::BRA*
means Inst cannot belong to such Jump Table pattern, thus returning early.