Skip to content

Commit abe2b92

Browse files
committed
Clarify operands of BRK, add tests
1 parent 12dc41e commit abe2b92

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed

bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,7 +1757,16 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
17571757
// Explicit Pointer Authentication check failed, see
17581758
// AArch64AsmPrinter::emitPtrauthCheckAuthenticatedValue().
17591759
return true;
1760+
case 0x1:
1761+
// __builtin_trap(), as emitted by Clang.
1762+
return true;
1763+
case 0x3e8: // decimal 1000
1764+
// __builtin_trap(), as emitted by GCC.
1765+
return true;
17601766
default:
1767+
// Some constants may indicate intentionally recoverable break-points.
1768+
// This is the case at least for 0xf000, which is used by
1769+
// __builtin_debugtrap() supported by Clang.
17611770
return false;
17621771
}
17631772
}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe -Wl,--emit-relocs
2+
// RUN: llvm-bolt-binary-analysis --scanners=pauth %t.exe 2>&1 | FileCheck %s
3+
4+
// Test what instructions can be used to terminate the program abnormally
5+
// on security violation.
6+
//
7+
// All test cases have the same structure:
8+
//
9+
// cbz x0, 1f // [a], ensures [c] is never reported as unreachable
10+
// autia x2, x3
11+
// cbz x1, 2f // [b]
12+
// [instruction under test]
13+
// 1:
14+
// ret // [c]
15+
// 2:
16+
// ldr x0, [x2]
17+
// ret
18+
//
19+
// This is to handle three possible cases: the instruction under test may be
20+
// considered by BOLT as
21+
// * trapping (and thus no-return): after being authenticated, x2 is ether
22+
// checked by LDR (if [b] is taken) or the program is terminated
23+
// immediately without leaking x2 (if [b] falls through to the trapping
24+
// instruction under test). Nothing is reported.
25+
// * non-trapping, but no-return (such as calling abort()): x2 is leaked if [b]
26+
// falls through. Authentication oracle is reported.
27+
// * non-trapping and falling-through (i.e. a regular instruction):
28+
// x2 is leaked by [c]. Authentication oracle is reported.
29+
30+
.text
31+
32+
.globl brk_key_ia
33+
.type brk_key_ia,@function
34+
brk_key_ia:
35+
// CHECK-NOT: brk_key_ia
36+
cbz x0, 1f
37+
autia x2, x3
38+
cbz x1, 2f
39+
brk 0xc470
40+
1:
41+
ret
42+
2:
43+
ldr x0, [x2]
44+
ret
45+
.size brk_key_ia, .-brk_key_ia
46+
47+
.globl brk_key_ib
48+
.type brk_key_ib,@function
49+
brk_key_ib:
50+
// CHECK-NOT: brk_key_ib
51+
cbz x0, 1f
52+
autia x2, x3
53+
cbz x1, 2f
54+
brk 0xc471
55+
1:
56+
ret
57+
2:
58+
ldr x0, [x2]
59+
ret
60+
.size brk_key_ib, .-brk_key_ib
61+
62+
.globl brk_key_da
63+
.type brk_key_da,@function
64+
brk_key_da:
65+
// CHECK-NOT: brk_key_da
66+
cbz x0, 1f
67+
autia x2, x3
68+
cbz x1, 2f
69+
brk 0xc472
70+
1:
71+
ret
72+
2:
73+
ldr x0, [x2]
74+
ret
75+
.size brk_key_da, .-brk_key_da
76+
77+
.globl brk_key_db
78+
.type brk_key_db,@function
79+
brk_key_db:
80+
// CHECK-NOT: brk_key_db
81+
cbz x0, 1f
82+
autia x2, x3
83+
cbz x1, 2f
84+
brk 0xc473
85+
1:
86+
ret
87+
2:
88+
ldr x0, [x2]
89+
ret
90+
.size brk_key_db, .-brk_key_db
91+
92+
// The immediate operand of BRK instruction may indicate whether the instruction
93+
// is intended to be a non-recoverable trap: for example, for this code
94+
//
95+
// int test_trap(void) {
96+
// __builtin_trap();
97+
// return 42;
98+
// }
99+
// int test_debugtrap(void) {
100+
// __builtin_debugtrap();
101+
// return 42;
102+
// }
103+
//
104+
// Clang produces the following assembly:
105+
//
106+
// test_trap:
107+
// brk #0x1
108+
// test_debugtrap:
109+
// brk #0xf000
110+
// mov w0, #42
111+
// ret
112+
//
113+
// In GCC, __builtin_trap() uses "brk 0x3e8" (i.e. decimal 1000) and
114+
// __builtin_debugtrap() is not supported.
115+
//
116+
// At the time of writing these test cases, any BRK instruction is considered
117+
// no-return by BOLT, thus it ends its basic block and prevents falling through
118+
// to the next BB.
119+
// FIXME: Make BOLT handle __builtin_debugtrap() properly from the CFG point
120+
// of view.
121+
122+
.globl brk_gcc_builtin_trap
123+
.type brk_gcc_builtin_trap,@function
124+
brk_gcc_builtin_trap:
125+
// CHECK-NOT: brk_gcc_builtin_trap
126+
cbz x0, 1f
127+
autia x2, x3
128+
cbz x1, 2f
129+
brk 0x3e8 // __builtin_trap()
130+
1:
131+
ret
132+
2:
133+
ldr x0, [x2]
134+
ret
135+
.size brk_gcc_builtin_trap, .-brk_gcc_builtin_trap
136+
137+
.globl brk_clang_builtin_trap
138+
.type brk_clang_builtin_trap,@function
139+
brk_clang_builtin_trap:
140+
// CHECK-NOT: brk_clang_builtin_trap
141+
cbz x0, 1f
142+
autia x2, x3
143+
cbz x1, 2f
144+
brk 0x1 // __builtin_trap()
145+
1:
146+
ret
147+
2:
148+
ldr x0, [x2]
149+
ret
150+
.size brk_clang_builtin_trap, .-brk_clang_builtin_trap
151+
152+
.globl brk_clang_builtin_debugtrap
153+
.type brk_clang_builtin_debugtrap,@function
154+
brk_clang_builtin_debugtrap:
155+
// CHECK-LABEL: GS-PAUTH: authentication oracle found in function brk_clang_builtin_debugtrap, basic block {{[^,]+}}, at address
156+
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x2, x3
157+
// CHECK-NEXT: The 0 instructions that leak the affected registers are:
158+
cbz x0, 1f
159+
autia x2, x3
160+
cbz x1, 2f
161+
brk 0xf000 // __builtin_debugtrap()
162+
1:
163+
ret
164+
2:
165+
ldr x0, [x2]
166+
ret
167+
.size brk_clang_builtin_debugtrap, .-brk_clang_builtin_debugtrap
168+
169+
// Conservatively assume BRK with an unknown immediate operand as not suitable
170+
// for terminating the program on security violation.
171+
.globl brk_unknown_imm
172+
.type brk_unknown_imm,@function
173+
brk_unknown_imm:
174+
// CHECK-LABEL: GS-PAUTH: authentication oracle found in function brk_unknown_imm, basic block {{[^,]+}}, at address
175+
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x2, x3
176+
// CHECK-NEXT: The 0 instructions that leak the affected registers are:
177+
cbz x0, 1f
178+
autia x2, x3
179+
cbz x1, 2f
180+
brk 0x3572
181+
1:
182+
ret
183+
2:
184+
ldr x0, [x2]
185+
ret
186+
.size brk_unknown_imm, .-brk_unknown_imm
187+
188+
// Conservatively assume calling the abort() function may be an unsafe way to
189+
// terminate the program, as there is some amount of instructions that would
190+
// be executed when the program state is already tampered with.
191+
.globl call_abort_fn
192+
.type call_abort_fn,@function
193+
call_abort_fn:
194+
// CHECK-LABEL: GS-PAUTH: authentication oracle found in function call_abort_fn, basic block {{[^,]+}}, at address
195+
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: autia x2, x3
196+
// CHECK-NEXT: The 0 instructions that leak the affected registers are:
197+
cbz x0, 1f
198+
autia x2, x3
199+
cbz x1, 2f
200+
b abort // a no-return tail call to abort()
201+
1:
202+
ret
203+
2:
204+
ldr x0, [x2]
205+
ret
206+
.size call_abort_fn, .-call_abort_fn
207+
208+
.globl main
209+
.type main,@function
210+
main:
211+
mov x0, 0
212+
ret
213+
.size main, .-main

0 commit comments

Comments
 (0)