Security implications for macOS

The ARMv8.3-A features adopted by Apple have significantly hardened both kernel and user-space security in macOS. The most profound impact comes from Pointer Authentication combined with later Armv8.x features like Branch Target Identification, which together implement a form of hardware-assisted Control-Flow Integrity (CFI).

Mitigating Return-Oriented and Jump-Oriented Programming (ROP/JOP)

By signing return addresses and critical function pointers, Pointer Authentication makes it extremely difficult for an attacker to divert execution by tampering with stored pointers. Any attempt to overwrite a return address (on stack) or a stored code pointer (in memory) with a malicious value will, with high probability, result in a PAC failure and a crash before the attacker-controlled address is used. This thwarts classic ROP attacks which rely on corrupting return addresses to execute gadget chains. Likewise, JOP attacks that overwrite function pointers or setjmp/longjmp buffers are defeated since the attacker cannot generate a valid PAC for a new target. The security is probabilistic (PAC uses ~16–24 bits out of 64, depending on configured VA space), but the odds of guessing a correct PAC are astronomically low (e.g. on the order of 1 in 2^16 or 2^24). Moreover, Apple’s per-process and per-boot key diversification means even if one PAC could somehow be forged, it wouldn’t generalize to others. The result is a massive reduction in viable gadget chains. In fact, studies by the U.S. NSA and Arm found that enabling PAC (and BTI) eliminates the vast majority of gadget opportunities – one analysis saw a 50× reduction in usable ROP/JOP gadgets in a Linux distro, and Arm’s own evaluation of glibc showed over 97% of gadgets were gone with PAC+BTI. Apple’s implementation goes further by splitting kernel vs user keys and host vs VM keys, closing potential loopholes where an attacker might try to reuse a pointer from one domain in another.

Branch Target Identification (BTI) to Stop JOP

Although BTI was formally introduced in ARMv8.5-A, Apple’s ARMv8.5-compliant CPUs (M1 and later) support it, and Apple has deployed it alongside PAC in macOS’s arm64e ABI. BTI tags legitimate indirect branch destinations with a special instruction at function entry (a BTI “landing pad”), and the CPU will fault if an indirect branch (BR/BLR) targets an address without that landing pad marking. This means an attacker cannot simply jump into the middle of a function or to an arbitrary gadget instruction; they are constrained to real function entry points that the compiler has marked as safe targets. By dramatically shrinking the set of allowable jump targets, BTI complements PAC: PAC protects pointers before use, and BTI adds a second check at the destination after an indirect jump. Apple’s compiler enables BTI by default when you build for arm64e (via -mbranch-protection flags). Together, PAC and BTI form a two-layer defense against control-flow hijacks: PAC defangs corrupt pointers and BTI reduces the chance of executing unintended sequences. An attacker now would need to find a chain of full functions (each starting at a valid BTI pad) and somehow forge valid PACs for all the pointers: a near-impossible task without a major breakthrough. This hardware CFI approach significantly raises the cost for exploits compared to the pre-Apple Silicon era.

Kernel and PAC

In the kernel, these mechanisms protect against privilege escalation and arbitrary code execution. Many macOS/iOS kernel exploits historically relied on overwriting function pointers or return addresses in kernel memory (since the kernel is monolithic and runs in a single address space). With XNU on Apple Silicon, an attacker with an arbitrary kernel memory write primitive can no longer easily plant a usable function pointer. For example, even if they overwrite a kernel exception return address or a stored function callback, when the kernel later authenticates that pointer, it will fail and panic the system rather than jump to the attacker’s payload. PAC also defends kernel data pointers in certain structures, making it harder to corrupt objects in a way that yields code execution. In short, ARMv8.3-A features have made the macOS kernel much more resilient to memory corruption: bugs that would have been readily exploitable on Intel Macs might merely crash an Apple Silicon Mac thanks to these hardware checks, closing off many avenues for escalation.

Mitigating memory corruption beyond CFI

While PAC/BTI specifically target control-flow, their presence indirectly strengthens memory safety. Attackers often chain memory corruption bugs to first craft an arbitrary read/write and then corrupt code pointers. PAC severely limits the utility of an arbitrary write, since most code and critical data pointers are PAC-protected. Other ARMv8.x features also contribute to memory safety – e.g., Apple’s M-series chips have support for the ARMv8.5 Memory Tagging Extension (MTE), a feature to catch buffer overflows/uses-after-free by tagging memory and pointers (Apple’s Xcode has an option for MTE-based heap debugging). Although not yet broadly enabled in macOS, the hardware capability means Apple could in the future deploy MTE to further guard against heap memory errors. Additionally, the ARMv8.3+ instruction set helps eliminate certain classes of errors; for instance, the JSCVT instruction ensures robust double-to-int conversion for JavaScript, which prevents bugs where out-of-range values could cause undefined behavior in JS engines – a subtle security improvement for browsers.

ROP gadget reduction and attack surface

The overall impact of ARMv8.3-A in macOS is a drastic reduction in viable exploit techniques. Classic ROP shellcode is largely dead on Apple Silicon; attackers have had to explore new strategies (for example, data-only attacks or logic bugs) since executing arbitrary code via stack smashing is so much harder. Even if an attacker bypasses one mitigation, they often hit another. A pertinent example was an early analysis of PAC on the iPhone A12: a researcher found a way to forge PACs by abusing a “signing gadget” (a function that would inadvertently sign attacker-chosen data). Apple responded by hardening the system (ensuring such signing oracles are not available to attackers, and incorporating context like the stack pointer into PAC calculations to bind pointers to their stack frame). This iterative hardening shows how Apple has adopted ARMv8.3’s features not just in hardware but as part of a holistic security model in macOS.

Side-channel and brute-force resistance

Because PAC is implemented in hardware and keys never leave the CPU registers, it is difficult for an attacker to retrieve the keys via software. Apple further blocks reading of PAC key registers even at EL1 when “Apple PA” (pointer auth) is enabled. Brute-force attempts to guess a PAC are impractical – not only due to the large key space, but also because failures immediately crash the process (or kernel) on use, and the PAC is refreshed each boot. Thus, an attacker can’t brute-force PACs without constant crashes and cannot mine PAC values easily. This strengthens the overall robustness of the system against systematic exploitation.

In summary, ARMv8.3-A’s security features as embraced by Apple have made macOS (and iOS) significantly more robust against memory corruption exploits. Apple’s design decisions – adopting arm64e ABI with PAC, using custom key diversification, and (in newer chips) enabling BTI and potentially memory tagging – illustrate a proactive security strategy leveraging hardware. As a result, macOS on Apple Silicon enjoys hardware-enforced kernel and user CFI, pointer integrity, and a much reduced attack surface for would-be malware and attackers.