Fixed
Status Update
Comments
pe...@arm.com <pe...@arm.com> #2
[Empty comment from Monorail migration]
kr...@arm.com <kr...@arm.com> #3
[Empty comment from Monorail migration]
pe...@arm.com <pe...@arm.com> #4
My expectation is that no-one here is affected directly by this as the CPU with the feature isn't available yet. My proposal is for Arm to fix this using the usual Phabricator process. If anyone has any objections please let me know?
di...@andric.com <di...@andric.com> #5
It would seem to be a rather esoteric issue, if this hardware is not generally available yet. :) And I don't know if the existence of the CPU itself is still under some non-disclosure?
But indeed, I see no reason why this would not be handled with a regular Phabricator review. Mentioning that it is a potentially security-related issue which is being fixed is optional, but it would make the intent clearer.
But indeed, I see no reason why this would not be handled with a regular Phabricator review. Mentioning that it is a potentially security-related issue which is being fixed is optional, but it would make the intent clearer.
pe...@arm.com <pe...@arm.com> #6
Thanks for the patience on this one. It took a while to come back with a good fix. This is now up for review in https://reviews.llvm.org/D155485 . Our best thoughts for a fix was to never elide the range check when branch-protection is enabled. It turns out that the range-check prevents an attacker taking advantage of the non BTI setting branch, and always using a BTI setting branch means adding a BTI clearing instruction at the start of each case statement, which increases the number of gadget starting points for indirect branches into the section.
pe...@arm.com <pe...@arm.com> #7
The fix has been committed as https://reviews.llvm.org/rG60b98363c7ed0a549be4d51ee07c32dc2bf47d2f and backported to LLVM 17 under https://github.com/llvm/llvm-project-release-prs/pull/527
Seeing as the commit message ofhttps://reviews.llvm.org/rG60b98363c7ed0a549be4d51ee07c32dc2bf47d2f and the comments in https://reviews.llvm.org/D155485 has much of the same information as this issue, I think we can make this public.
Seeing as the commit message of
pe...@arm.com <pe...@arm.com> #8
Closing and making issue public as fix has been committed and backported to LLVM17. All details here are in commit messages and patches.
Description
A subset of the indirect branches are classified as BTI setting. When the BTI feature is enabled these BTI setting branches can only target BTI clearing instructions, otherwise an INVSTATE usage fault is generated. This limits the number of JOP gadgets that an attacker can use.
We (Arm) have found a case where LLVM can select a non BTI setting branch instruction MOV PC, Rn which does not have to land on a BTI clearing instruction. If the attacker can control Rn they can bypass the BTI protection.
The specific problem is the lowering of ARM::t2BR_JT which can be used to implement jump tables expands to MOV PC, Rn in Arm v8.1-M rather than the BTI setting BX Rn. Note that this requires a very large switch statement as usually the TBH and TBB table branch instructions are used.
An example that we have made that places Rn under control of the attacker. Note that the __llvm_unreachable() is required for the compiler to elide the range check.
// File bti.c
int v;
// Attacker is assumed to control value of x
int *foo(int *x) {
switch (*++x) {
case 0:
// A large amount of data to force an indirect branch.
asm(".space 140000");
v = 42;
break;
case 1:
v = 1337;
break;
case 2:
v = 15532;
break;
case 3:
v = 1234;
break;
default:
// User is telling compiler that all other values
// are undefined behavior. Compiler determines that
// a range check is unnecessary.
__builtin_unreachable();
}
return x;
}
Results in:
foo:
.fnstart
bti
ldr r2, [r0, #4]!
movw r1, #1337
adr.w r3, .LJTI0_0
add.w r3, r3, r2, lsl #2 // r3 determined by base of jump table + attacker controlled offset
mov pc, r3 // non BTI setting branch to r3
.p2align 2
.LJTI0_0:
b.w .LBB0_2
b.w .LBB0_5
b.w .LBB0_3
b.w .LBB0_4
...
The Arm v8.1-M BTI extension is not yet available in consumer hardware. The first CPU to support it is the Cortex-M85 due this year (
We have a fix (use BX Rn) that we can upstream once we've checked if anyone is developing software for Arm v8.1-M