AD3017: EnableArmBTI¶
Summary¶
| Property | Value |
|---|---|
| ID | AD3017 |
| Name | EnableArmBTI |
| Category | Security |
| Severity | Warning |
| Applies to | ELF (Linux/Unix) - AArch64 |
Description¶
This rule checks that AArch64 ELF binaries have ARM Branch Target Identification (BTI) enabled. BTI is a hardware security feature that protects against Jump-Oriented Programming (JOP) and Call-Oriented Programming (COP) attacks.
Why This Matters¶
ARM BTI is the ARM ecosystem's answer to control-flow hijacking attacks. As ARM processors become dominant in mobile, embedded, and increasingly server environments, BTI provides essential protection against JOP and COP attacks.
ARM in Critical Infrastructure¶
ARM processors are everywhere:
| Domain | Examples |
|---|---|
| Mobile | All modern smartphones |
| Cloud | AWS Graviton, Ampere |
| Embedded | IoT, automotive |
| Apple | M1/M2/M3 Macs |
| Windows | Snapdragon PCs |
Securing ARM binaries is increasingly critical.
JOP/COP on ARM¶
ARM has rich indirect branch instructions:
blr x0 ; Branch and Link to register (indirect call)
br x1 ; Branch to register (indirect jump)
ret ; Return (special case of BR x30)
Without BTI, attackers can redirect any of these to arbitrary code.
How BTI Works¶
Without BTI:
blr x0 → Can branch to ANY instruction
With BTI:
blr x0 → Target MUST be BTI instruction
Otherwise → exception
BTI variants:
bti c ; Valid target for BLR (calls)
bti j ; Valid target for BR (jumps)
bti jc ; Valid for both calls and jumps
Gadget Elimination¶
Normal binary:
Every instruction is potential gadget landing
Millions of possible targets
BTI-enabled binary:
Only BTI instructions are valid targets
Compiler controls where these appear
Dramatically reduced attack surface
BTI Instruction Overhead¶
| Scenario | Overhead |
|---|---|
| Indirect call targets | One BTI instruction (4 bytes) |
| Function pointers | BTI at each target |
| Virtual methods | BTI in vtable targets |
| Overall | 1-3% code size, minimal runtime |
Hardware Support¶
| Processor | BTI Support |
|---|---|
| ARM Cortex-A78+ | Yes |
| ARM Neoverse N1+ | Yes |
| Apple M1+ | Yes (called BTI/PAC) |
| Qualcomm Snapdragon 8+ | Yes |
Backward Compatibility¶
BTI instructions execute as NOPs on older hardware:
On BTI-enabled CPU:
- BTI instructions enforced
- Invalid targets cause exception
On older CPU:
- BTI instructions execute as NOP
- No protection, but code works
- Safe for mixed deployment
- JOP/COP protection: BTI restricts where indirect branches can land
- Hardware enforcement: Uses CPU features for control-flow protection
- Landing pad validation: Only
BTIinstructions are valid targets for indirect branches - ARM ecosystem: Standard security feature on modern ARM64 platforms
How BTI Works¶
When BTI is enabled:
1. Each valid indirect branch target must begin with a BTI instruction
2. The BTI instruction specifies which types of branches are allowed (call, jump, or both)
3. If an indirect branch lands elsewhere, the CPU raises an exception
4. This significantly reduces the gadgets available to attackers
Performance Considerations¶
BTI has negligible runtime overhead due to hardware implementation:
| Metric | Impact |
|---|---|
| Runtime overhead | <0.5% typical |
| Code size increase | 1-3% (BTI instructions) |
| Memory overhead | None |
Why BTI is nearly free: - BTI instructions are effectively NOPs on the normal execution path - Hardware validation happens during instruction fetch - No additional memory accesses or pipeline stalls
Comparison with software CFI:
| Protection | Overhead | Precision |
|---|---|---|
| BTI (hardware) | <0.5% | Function-level |
| Software CFI | 5-20% | Type-level possible |
Combined with PAC:
Using -mbranch-protection=standard enables both BTI and PAC with approximately 1-2% total overhead for comprehensive protection.
How to Fix¶
Compile with branch protection¶
# Enable BTI
gcc -mbranch-protection=bti -o myapp myapp.c
# Enable both BTI and PAC (recommended)
gcc -mbranch-protection=standard -o myapp myapp.c
# Clang equivalent
clang -mbranch-protection=bti+pac-ret -o myapp myapp.c
Verify the fix¶
readelf -n myapp | grep -i "BTI"
# Should show BTI in properties
# Or check for BTI instructions in disassembly
objdump -d myapp | grep -c "bti"
Example¶
Fail: Binary does not have BTI enabled
Pass: Binary has BTI enabled
Requirements¶
- Compiler: GCC 9+ or Clang 8+
- CPU: ARMv8.5-A or later (with FEAT_BTI)
- Kernel: Linux 5.8+ for BTI support
- glibc: 2.32+ for full support
See Also¶
- AD3018: EnableArmPAC - Pointer Authentication
- ARM BTI Documentation