In Return-oriented programming (ROP) and Jump-oriented programming (JOP), we explored features that Arm introduced to the Arm architecture to mitigate against JOP-style and ROP-style attacks. Now we will look at the compiler support for these features, and how enabling these protections affects the number of that are gadgets available to attackers.
In this section, we refer to these versions of Arm Compiler 6 and Gnu C Compiler (GCC):
- Arm Compiler 6.11
- GCC 9.1
Compiler support for these features continues to evolve. Precise figures will vary based on the versions that you use.
Build an image with pointer authentication and branch target identification
For Arm Compiler 6, GCC and LLVM generation of pointer authentication and BTI-enabled code is controlled by:
<protection> can be any combination of:
pac-retenables return address signing for non-leaf functions using the A-key.
+leafincreases the scope of return address signing to include leaf functions.
+b-keyuses B-key instructions to sign addresses instead of A-key instructions.
btiprotects code using Branch Target Identification.
standardturns on all types of branch protection.
- Currently standard implies
noneturns off all types of branch protection.
- This is the default if the
-mbranch-protectionflag is not provided.
Whether the combined or NOP-compatible instructions are generated depends on the architecture version that the code is built for. When building for Armv8.3-A, or later, the compiler will use the combined operations. When building for Armv8.2-A, or earlier, it will use the NOP compatible instructions. For example:
Note: The function used in this example was taken from the example that accompanies our guide Arm CoreLink Generic Interrupt Controller v3 and v4 Overview and built with Arm Compiler 6.
The compiler generates the instructions that are required to perform signing and authentication. Generating and configuring keys is the responsibility of supervising software, typically an operating system.
Reduction in available gadgets
GLIBC is a large library that is used in C or C++ applications. This means that it is a good target for attackers, and a good place for us to see the effect of applying the measures to mitigate attacks. Arm used this tool to measure the number of available gadgets and modified the tool to fit our requirements.
The following graph shows the number of gadgets before and after the compiler options were enabled:
By enabling both pointer authentication and branch target identification, the number of gadgets that are available reduces by 97.65%.
Effect on code size
The protection described in the preceding section is helpful but comes at a cost. One obvious cost is the increase in code size. Here is an analysis of this cost:
The graph shows that the code size effect on GLIBC is minimal. Even though turning on both the mitigations leads to a 2.9% code size increase, this increase is smaller when compiling with
-march=armv8.3-a. Compiling for Armv8.3-A allows the compiler to use fused authenticate and return instructions. This means that, for Armv8.3-A, the code size increase is only 1.6%.