Skip to content

ARM Pointer Authentication

Armv8.3 cryptographic CFI: pointer'ları (return address'ler, code/data pointer'ları) kullanılmayan high bit'lerde saklanan keyed bir PAC ile sign'la ve kullanmadan önce authenticate et — corrupt edilmiş bir pointer check'i fail eder ve dereference'ta fault verir.

Mechanism

Neden çalışır

Bir 64-bit virtual address, 64 bit'ten çok daha azını kullanır, dolayısıyla bir pointer'ın üst bit'leri boştadır. PAC, keyed bir cryptographic signature'ı o bit'lerin içine tıkar. Kullanılabilir bir pointer forge etmek için bir attacker'ın o değer için doğru PAC'ı üretmesi gerekir — secret key olmadan infeasible'dır.

  • PAC*, (pointer value, 64-bit bir context/tweak, 128-bit secret bir key) üzerinden bir PAC hesaplar ve onu pointer'ın kullanılmayan bit'lerine yazar.
  • AUT*, PAC'ı yeniden hesaplar ve doğrular, başarı durumunda onu strip eder.
  • Failure durumunda hardware branch yapmaz; "an error code is placed in the pointer's extension bits so that a fault is triggered if the pointer is dereferenced" — corrupt high bit'ler adresi non-canonical yapar, dolayısıyla onu kullanmak bir translation fault raise eder.

Cipher QARMA'dır (QARMA-64: 128-bit key, plaintext olarak 64-bit pointer, tweak olarak 64-bit context); implementation'lar başkasını ikame edebilir. Beş key vardır: APIAKey, APIBKey (instruction pointer'ları), APDAKey, APDBKey (data pointer'ları), APGAKey (keyfi data'nın generic signing'i). Standart pac-ret ABI'si, return address'i prologue'da context olarak SP ile sign'lar ve epilogue'da authenticate eder.

Invariant şu: yalnızca key'i tutan code, authenticate olan bir pointer mint edebilir, dolayısıyla attacker adreslerini ikame eden ROP/JOP, AUT*'ta fail eder.

Walkthrough

1. Return-address signing ile build et.

$ clang --target=aarch64-linux-gnu -mbranch-protection=pac-ret -c f.c
# or: gcc -mbranch-protection=pac-ret

2. Prologue/epilogue PAC instruction'ları kazanır. Context olarak SP ile A instruction key'ini kullanarak:

foo:
    paciasp                 ; sign LR with APIAKey, context = SP
    stp   x29, x30, [sp,#-16]!
    ...
    ldp   x29, x30, [sp],#16
    autiasp                 ; authenticate LR; corrupted -> poisoned pointer
    ret                     ; ret to a non-canonical addr -> translation fault

(PACIBSP/AUTIBSP, B key'ini kullanır; XPACI, bir PAC'ı strip eder; RETAB, BLRAA vb. auth'u branch'in içine katlar.)

3. Bypass denemesinin fault verdiğini gözlemle. Stack'teki kayıtlı LR'ı overwrite et; autiasp'ten sonra değerin top bit'leri poison'lanır, dolayısıyla ret attacker'ın gadget'ına değil, geçersiz bir adrese jump eder → SIGSEGV.

Key'ler, oracle'lar ve reuse

PAC'ın gücü, key'in gizliliği ve context'in benzersizliğidir. Geçerli bir (pointer, PAC) çifti farklı bir context'te yeniden kullanılabiliyorsa ya da code, attacker data'sını sign'layıp sonucu açığa çıkarmaya zorlanabiliyorsa (signing oracle), CFI key bilinmeden bypass edilebilir. Same-context pointer swap'leri (örn. ikisi de SP ile sign'lanmış iki return site'ı) bilinen bir zayıflıktır.

Mitigation

(Residual risk.) PAC, hangi signed pointer'ın kullanıldığını değil, yalnızca geçerli biçimde sign'lanmış bir tanesinin kullanıldığını authenticate eder — bu da reuse saldırılarına olanak tanır. Forward edge'in de kapsanması için BTI ile (pac-ret+bti olarak) eşleşir.

References