Skip to content

AD5007: EnableArmPACMachO

Summary

Property Value
ID AD5007
Name EnableArmPACMachO
Category Security
Severity Warning
Applies to Mach-O ARM64 (Apple Silicon)

Description

ARM Pointer Authentication Code (PAC) provides hardware-based protection against Return-Oriented Programming (ROP) attacks on Apple Silicon (ARM64). PAC signs return addresses and function pointers with a cryptographic signature that is verified before use.

How It Works

The rule checks for:

  1. PAC-related symbols (__ptrauth, ptrauth_sign, etc.)
  2. Compilation for arm64e architecture in DWARF debug info

When PAC is enabled, the CPU: - Signs pointers when they are stored (e.g., return addresses) - Verifies signatures when pointers are used - Faults if a signature doesn't match (tampering detected)

Why This Matters

Apple Silicon includes hardware Pointer Authentication that makes ROP attacks cryptographically expensive. PAC signs every return address and function pointer, making exploitation extremely difficult even with full memory corruption.

Cryptographic Protection

PAC uses hardware cryptography:

Without PAC:
  Stack: [...][ret_addr][...]
  Attacker overwrites ret_addr
  Function returns to attacker's address

With PAC:
  Stack: [...][signed_ret_addr][...]
  signature = QARMA(ret_addr, context, secret_key)
  Attacker overwrites ret_addr
  Signature verification fails
  CPU faults → crash instead of exploitation

Why PAC Is Stronger Than Canaries

Protection Mechanism Bypass
Stack canary Random value Info leak reveals canary
PAC Cryptographic signature Requires key extraction (impossible)

Apple Silicon PAC Implementation

Chip PAC Support
M1/M1 Pro/Max Full
M2/M2 Pro/Max Full
M3/M3 Pro/Max Full
A12+ Full (iOS)

arm64 vs arm64e

Architecture PAC Status
arm64 No Standard, widely compatible
arm64e Yes Enhanced security, Apple Silicon

arm64e enables PAC instructions.

Context Binding

PAC signatures include context:

Signature = f(pointer, context, key)

Context examples:
  - Stack pointer (for return addresses)
  - Type information
  - Object pointer

Reusing a signed pointer in wrong context = verification failure

Performance

Operation Overhead
Sign pointer 1-2 cycles
Verify pointer 1-2 cycles
Overall app <1%

Hardware implementation is extremely fast.

iOS Deployment

iOS Version PAC Status
iOS 12+ Kernel uses PAC
iOS 14+ More userspace PAC
iOS 15+ Widespread PAC
  • Hardware-enforced protection: Cannot be bypassed by software
  • ROP mitigation: Return addresses cannot be reliably overwritten
  • JOP mitigation: Function pointers are protected
  • Apple Silicon native: Full support on M1/M2/M3 chips

Performance Considerations

PAC on Apple Silicon is extremely efficient:

Metric Impact
Runtime overhead <1%
Sign/verify cost 1-2 cycles
Memory overhead None
arm64e overhead vs arm64 Negligible

Why Apple Silicon PAC is fast: - Dedicated cryptographic hardware in the CPU - Signing/verification happens in parallel with other operations - No memory accesses required - Optimized for the common case (no tampering)

Benchmark data:

Workload arm64 arm64e Difference
Compute-heavy 100% 100.3% <0.5%
Call-heavy 100% 101% ~1%
Real apps 100% 100.5% <1%

Resolution

Targeting arm64e

The arm64e architecture enables PAC. Standard arm64 does not.

Xcode:

  1. Select your target
  2. Go to Build Settings → Architectures
  3. Add arm64e to Architectures

Command Line:

# Compile for arm64e (PAC-enabled)
clang -arch arm64e source.c -o binary

CMake:

set(CMAKE_OSX_ARCHITECTURES "arm64e")

Using Pointer Authentication Intrinsics

For explicit pointer signing:

#include <ptrauth.h>

// Sign a function pointer
void (*signed_ptr)(void) = ptrauth_sign_unauthenticated(
    func_ptr,
    ptrauth_key_function_pointer,
    0
);

When to Suppress

This rule may be suppressed for:

  • Compatibility requirements: Need to run on older hardware
  • Third-party code: Libraries not compiled for arm64e
  • Universal binaries: Supporting both arm64 and arm64e

Important Notes

  • arm64e binaries only run on Apple Silicon
  • Universal binaries can contain both arm64 and arm64e slices
  • iOS has limited support for third-party arm64e binaries
  • PAC is different from ARM BTI (Branch Target Identification)

References