Skip to content

PaX/grsecurity RAP

RAP (Reuse Attack Protector), grsecurity'nin compiler tabanlı CFI'sıdır: her indirect call/jump'ta (forward edge) bir type-hash kontrolü, artı return address'lerin register-keyed bir XOR "şifrelemesi" (backward edge); özel hardware olmadan ROP/JOP'u yener.

Mechanism

Neden çalışır

Code-reuse saldırıları (ROP, JOP, COOP), bir indirect transfer'ı orijinal programın hiç amaçlamadığı bir yere düşürerek control flow'u hijack eder: üzerine yazılmış bir return address, bozulmuş bir function pointer, sahte bir vtable. Meşru control-flow graph, her böyle site'ta yalnızca küçük bir hedef kümesine izin verir. RAP bu graph'ı iki edge'de uygular.

Forward edge (indirect call/jump). RAP, compile zamanında her fonksiyonun signature'ından ve her indirect call site'ının beklenen signature'ından bir type hash türetir. Call site'ı, hedefin yanında saklanan hash'i site'ın beklediği hash ile karşılaştıracak şekilde instrument eder; bir uyumsuzluk abort eder. Tüm type bilgisi tek bir compilation unit'te yaşadığı için, RAP'in bütün-program link-time analizine ihtiyacı yoktur. Granülerlik annotation ile sıkılaştırılabilir — örn. bir parametre type'ını ayrı bir sensitive_string olarak yeniden adlandırmak, semantiği değiştirmeden başka türlü özdeş iki signature sınıfını ayırır.

Backward edge (return'ler). Bir fonksiyona girişte RAP, geri döneceği adresi — kaydedilmiş return address'i herhangi bir kod bozabilmeden önce — bir reserved CPU register'da tutulan bir secret key kullanarak "şifreler". Return'de, instrument edilmiş epilogue çözer ve karşılaştırır; bozulmuş bir return address artık eşleşmez. Key sık sık rotate edilebilir (kernel'de syscall başına, scheduler iterasyonu başına); böylece tek-seferlik bir key leak'inin ömrü kısadır.

Invariant: her indirect branch aynı type'tan bir fonksiyonu hedeflemeli ve her return, secret key altında girişte kaydedilen adrese ulaşmalıdır. İkisi de deterministiktir ve shadow-stack hardware'i veya branch-target instruction'ları gerektirmez.

Walkthrough

RAP, hem Linux kernel'ine hem userland binary'lerine uygulanabilen bir GCC plugin olarak gelir (grsecurity/PaX patch'inin ve toolchain'inin parçası). Onu doğrudan çağırmak yerine kernel hardening config'i üzerinden etkinleştirir ve instrumentation'ını gözlemlersiniz.

1. Kavramsal forward-edge instrumentation. Bir function pointer üzerinden bir indirect call, bir type-hash karşılaştırması ile sarılır. Şematik olarak:

    ; before calling *%rax, check the hash stored just before the target
    cmp    $RAP_HASH_foo_sig, -8(%rax)   ; expected call-site type hash
    jne    .Lrap_violation               ; abort on mismatch
    call   *%rax

RAP_HASH_foo_sig sabiti, call site'ının bildirilen function-pointer type'ından hesaplanır; -8(%rax)'teki değer, eşleşen bir type'a sahip her address-taken fonksiyonun yanına compiler tarafından emit edilir.

2. Kavramsal backward-edge instrumentation. Prologue, kaydedilmiş return address'i bir reserved register'daki context başına key ile karıştırır; epilogue onu doğrular:

foo:
    ; prologue: "encrypt" return addr with key in reserved reg (e.g. %r12)
    xor    %r12, (%rsp)        ; conceptual: cookie return address
    ...
    ; epilogue: undo and verify before RET
    xor    %r12, (%rsp)
    cmp    saved_ret, (%rsp)   ; mismatch => corrupted => abort
    jne    .Lrap_violation
    ret

(Yayınlanan RAP örneği, return address'in giriş-zamanı store/compare'ini göstermek için 0xaabbccdd gibi bir cookie değeri kullanır.)

3. Bir reuse denemesi durdurulur. Kaydedilmiş return address'in üzerine bir gadget adresi yazan bir stack overflow, register-keyed cookie ile eşleşmeyen bir değer üretir; bu yüzden epilogue, ret control'ü aktarmadan önce abort eder. Yanlış-type bir fonksiyona işaret eden bozulmuş bir function pointer, forward-edge hash karşılaştırmasında başarısız olur.

Type CFI, type'lar çakıştığında kabadır

Forward-edge type CFI, signature hash'i call site ile eşleşen herhangi bir fonksiyona izin verir. Birçok farklı fonksiyon bir signature paylaşabilir, bu yüzden tek bir type sınıfı içinde yeterince zengin bir gadget kümesi hâlâ kısıtlı reuse'a izin verir. RAP'in annotation mekanizması sınıfları daraltır ama collision'ları ortadan kaldıramaz.

Mitigation

(Artık risk / bypass.) RAP'in backward edge'i, key register'ın gizliliğine dayanması anlamında olasılıksaldır: key'i leak eden bir saldırgan (ve key henüz rotate olmamışsa) return address'ler için geçerli cookie'ler forge edebilir. Sık rekeying bu pencereyi daraltır. Forward edge, type-hash collision'ları ile sınırlıdır; aynı-signature gadget zincirlerine ve control-flow graph'ını hiç ihlal etmeyen data-only saldırılarına yer bırakır. Intel CET shadow stack gibi hardware backward-edge savunmaları ve forward-edge Intel CET IBT ile, ayrıca type-CFI akrabası Clang CFI / kernel CFI ile karşılaştırın.

References