iOS Exploiting

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

iOS Exploit Mitigations

1. Code Signing / Runtime Signature Verification

Introduced early (iPhone OS → iOS) Bu, temel korumalardan biridir: tüm yürütülebilir kod (uygulamalar, dynamic libraries, JIT-ed code, extensions, frameworks, caches) Apple’ın trust köküne dayanan bir sertifika zinciri ile kriptografik olarak imzalanmış olmalıdır. Çalışma zamanında, bir ikili belleğe yüklenmeden önce (veya belirli sınırlar arasında atlamalar yapılmadan önce), sistem imzayı doğrular. Kod değiştirilmişse (bit-flip, patch) veya imzasızsa yükleme başarısız olur.

  • Engeller: exploit zincirlerindeki “klasik payload drop + execute” aşamasını; keyfi kod enjeksiyonunu; mevcut bir ikiliyi kötü amaçlı mantık eklemek için değiştirmeyi.
  • Mekanizma detayı:
  • Mach-O loader (ve dynamic linker) kod sayfalarını, segmentleri, entitlements, team ID’leri ve imzanın dosyanın içeriğini kapsadığını kontrol eder.
  • JIT cache’leri veya dinamik üretilen kod gibi bellek bölgeleri için, Apple sayfaların imzalanmış olmasını veya özel API’ler aracılığıyla doğrulanmasını zorunlu kılar (ör. mprotect ile code-sign kontrolleri).
  • İmza entitlements ve identifier’ları içerir; OS belirli API’lerin veya ayrıcalıklı yeteneklerin belirli entitlements gerektirdiğini ve bunların taklit edilemeyeceğini uygular.
Example Bir exploit bir süreçte kod yürütmesi elde edip shellcode’u heap’e yazıp ona atlamaya çalıştığını varsayın. iOS’ta o sayfanın executable olarak işaretlenmesi ve ayrıca code-signature kısıtlarını karşılaması gerekir. Shellcode Apple’ın sertifikasıyla imzalanmadığı için atlama başarısız olur veya sistem o bellek bölgesini executable yapmayı reddeder.

2. CoreTrust

Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust, ikililerin runtime imza doğrulamasını Apple’ın root sertifikasına karşı yapan alt sistemdir (kullanıcı alanı trust store’larına güvenmek yerine).

  • Engeller: kurulum sonrası ikililerin tahrifini, system kütüphanelerini veya kullanıcı uygulamalarını swap/patch etmeye çalışan jailbreaking tekniklerini; trusted ikililerin kötü amaçlı muadilleri ile değiştirilerek sistemi kandırmayı.
  • Mekanizma detayı:
  • Yerel bir trust veritabanına veya sertifika önbelleğine güvenmek yerine, CoreTrust doğrudan Apple’ın root’una referans verir veya intermediate sertifikaları güvenli bir zincirde doğrular.
  • Mevcut ikililere (ör. filesystem üzerinden) yapılan değişikliklerin tespit edilip reddedilmesini sağlar.
  • Entitlements, team ID’leri, code signing flag’leri ve diğer metadata’yı yükleme zamanında ikiliye bağlar.
Example Bir jailbreak `SpringBoard` veya `libsystem`’i yamanmış bir versiyonla değiştirmeye çalışabilir. Ancak OS loader veya CoreTrust kontrol ettiğinde imza uyuşmazlığını (veya değiştirilmiş entitlements’ı) görür ve yürütmeyi reddeder.

3. Data Execution Prevention (DEP / NX / W^X)

Introduced in many OSes earlier; iOS had NX-bit / w^x for a long time DEP, yazılabilir (data) sayfaların executable olmayan, executable sayfaların ise yazılamaz olmasını zorunlu kılar. Heap veya stack bölgesine shellcode yazıp bunu yürütmek mümkün değildir.

  • Engeller: doğrudan shellcode yürütmeyi; klasik buffer-overflow → injected shellcode’a atlama senaryosunu.
  • Mekanizma detayı:
  • MMU / bellek koruma flag’leri (page table’lar aracılığıyla) ayrımı uygular.
  • Yazılabilir bir sayfayı executable yapmak için yapılan her girişim sistem kontrolünü tetikler (veya yasaklanır ya da code-sign onayı gerektirir).
  • Birçok durumda, sayfaları executable yapmak OS API’leri üzerinden ek kısıtlar veya kontroller uygular.
Example Bir overflow shellcode’u heap’e yazar. Saldırgan `mprotect(heap_addr, size, PROT_EXEC)` yaparak onu executable yapmayı dener. Ancak sistem bunu reddeder veya yeni sayfanın code-sign kısıtlarını geçmesi gerektiğini doğrular (ki shellcode bunu sağlayamaz).

4. Address Space Layout Randomization (ASLR)

Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR, kütüphanelerin, heap’in, stack’in vb. temel bellek bölgelerinin taban adreslerini her süreç başlatıldığında rastgeleleştirir. Gadget’ların adresleri çalıştırmalar arasında değişir.

  • Engeller: ROP/JOP için gadget adreslerini sabitlemeyi; statik exploit zincirlerini; bilinen offset’lere kör atlamayı.
  • Mekanizma detayı:
  • Yüklenen her kütüphane / dynamic module rastgele bir offset ile rebase edilir.
  • Stack ve heap taban pointer’ları (belirli entropi sınırları içinde) rastgeleleştirilir.
  • Bazen diğer bölgeler (ör. mmap allocations) da rastgeleleştirilir.
  • information-leak mitigations ile beraber kullanıldığında, saldırganın önce runtime’da taban adresleri keşfetmek için bir adres leak etmesi gerekir.
Example Bir ROP zinciri `0x….lib + offset`’teki gadget’ı bekler. Ancak `lib` her çalıştırmada farklı bir yere taşındığından, sabitlenmiş zincir başarısız olur. Bir exploit önce modülün base adresini leak etmelidir ki gadget adresleri hesaplanabilsin.

5. Kernel Address Space Layout Randomization (KASLR)

Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) Kullanıcı ASLR’sine benzer şekilde, KASLR önyükleme sırasında kernel text ve diğer kernel yapıların tabanını rastgeleleştirir.

  • Engeller: kernel seviyesinde kod veya veri sabit lokasyonuna dayanan exploitleri; statik kernel exploitlerini.
  • Mekanizma detayı:
  • Her boot’ta kernel’in base adresi (belirli bir aralık içinde) rastgeleleştirilir.
  • Kernel veri yapıları (ör. task_structs, vm_map, vb.) de yeniden yerleştirilebilir veya offsetlenebilir.
  • Saldırganlar kernel pointer’larını leak etmeden önce kernel referanslarını veya offset’leri hesaplamak için bilgi açığa çıkarma (leak) zafiyetleri kullanmak zorundadır.
Example Bir yerel zafiyet kernel fonksiyon pointer’ını (ör. `vtable` içindeki) `KERN_BASE + offset`’te bozmayı hedefler. Ancak `KERN_BASE` bilinmediğinden saldırgan önce onu leak etmelidir (ör. bir read primitive ile) ki doğru adres hesaplanıp bozulabilsin.

6. Kernel Patch Protection (KPP / AMCC)

Introduced in newer iOS / A-series hardware (post around iOS 15–16 era or newer chips) KPP (aka AMCC) kernel text sayfalarının bütünlüğünü (hash veya checksum aracılığıyla) sürekli izler. Eğer izinsiz bir tahrifat (patch, inline hook, kod değişikliği) tespit edilirse kernel panic veya reboot tetikler.

  • Engeller: kalıcı kernel patch’leri (kernel talimatlarını değiştirme), inline hook’lar, statik fonksiyon overwrite’ları.
  • Mekanizma detayı:
  • Donanımsal veya firmware tabanlı bir modül kernel text bölgesini izler.
  • Sayfaları periyodik veya talep üzerine yeniden hash’ler ve beklenen değerlerle karşılaştırır.
  • Eğer benign update pencerelerinin dışında uyuşmazlıklar görülürse cihazı panic’e sokar (kalıcı kötü amaçlı patch’ten kaçınmak için).
  • Saldırganların ya tespit pencerelerinden kaçması ya da meşru patch yollarını kullanması gerekir.
Example Bir exploit kernel fonksiyon prologunu (ör. `memcmp`) patchleyerek çağrıları yakalamaya çalışır. Ancak KPP kod sayfasının hash’inin beklenenle eşleşmediğini görür ve kernel panic tetiklenir; cihaz patch stabilize olmadan çöker.

7. Kernel Text Read‐Only Region (KTRR)

Introduced in modern SoCs (post ~A12 / newer hardware) KTRR, donanım tarafından uygulanan bir mekanizmadır: kernel text boot sırasında kilitlendikten sonra EL1’den (kernel) okunamaz-yazılamaz hale gelir; böylece kod sayfalarına sonradan yazma engellenir.

  • Engeller: boot sonrası kernel koduna yapılacak herhangi bir değişiklik (ör. patching, yerinde code injection) EL1 ayrıcalık düzeyinde.
  • Mekanizma detayı:
  • Boot sırasında (secure/bootloader aşamasında), memory controller (veya güvenli bir donanım birimi) kernel text’i içeren fiziksel sayfaları read-only olarak işaretler.
  • Bir exploit tam kernel ayrıcalıkları ele geçirse bile bu sayfalara yazamaz.
  • Bunları değiştirmek için saldırganın önce boot zincirini kompromize etmesi veya KTRR’yi atlatarak subvert etmesi gerekir.
Example Bir privilege-escalation exploit EL1’e atlayıp kernel fonksiyonuna (ör. `syscall` handler) bir trampoline yazmaya çalışır. Ancak sayfalar KTRR tarafından read-only kilitli olduğundan yazma başarısız olur (veya fault tetiklenir), dolayısıyla patch uygulanamaz.

8. Pointer Authentication Codes (PAC)

Introduced with ARMv8.3 (hardware), Apple beginning with A12 / iOS ~12+

  • PAC, pointer değerlerinin (return adresleri, function pointer’lar, bazı data pointer’lar) tahrifini tespit etmek için ARMv8.3-A’da tanıtılmış bir donanım özelliğidir; pointer’ın kullanılmayan üst bitlerine küçük bir kriptografik imza (“MAC”) gömülür.
  • İmza (“PAC”), pointer değeri ile bir modifier (bir bağlam değeri, ör. stack pointer veya ayırt edici bir veri) üzerinden hesaplanır. Böylece aynı pointer değeri farklı bağlamlarda farklı PAC üretir.
  • Kullanım zamanında, pointer deref edilmeden veya o pointer ile dallanmadan önce bir authenticate talimatı PAC’ı kontrol eder. Eğer geçerliyse PAC temizlenir ve saf pointer elde edilir; geçersizse pointer “poisoned” olur (veya bir fault yükseltilir).
  • PAC üretmek/doğrulamak için kullanılan anahtarlar ayrıcalıklı register’larda (EL1, kernel) bulunur ve user modundan doğrudan okunamaz.
  • Birçok sistemde tüm 64 bit pointer’lar kullanılmadığı için (ör. 48-bit adres alanı), üst bitler “boş” kalır ve PAC adresi etkilemeden bu bitlere yerleştirilebilir.

Architectural Basis & Key Types

  • ARMv8.3 beş 128-bit anahtar tanıtır (her biri iki 64-bit sistem register’ı ile uygulanır).

  • APIAKey — instruction pointer’lar için (domain “I”, key A)

  • APIBKey — ikinci instruction pointer anahtarı (domain “I”, key B)

  • APDAKey — data pointer’lar için (domain “D”, key A)

  • APDBKey — data pointer’lar için (domain “D”, key B)

  • APGAKey — generic key, pointer olmayan veri veya diğer genel kullanımlar için

  • Bu anahtarlar ayrıcalıklı sistem register’larında saklanır (sadece EL1/EL2 vb. erişilebilir), user modunda erişilemez.

  • PAC, kriptografik bir fonksiyon ile (ARM QARMA algoritmasını önerir) şu girdilerle hesaplanır:

  1. Pointer değeri (canonical kısmı)
  2. Bir modifier (stack pointer gibi bir bağlam değeri)
  3. Gizli anahtar
  4. İçsel tweak mantığı Eğer ortaya çıkan PAC pointer’ın üst bitlerinde saklananla eşleşirse authentication başarılı olur.

Instruction Families

İsimlendirme şu şekildedir: PAC / AUT / XPAC, ardından domain harfleri.

  • PACxx talimatları bir pointer’ı sign eder ve PAC ekler
  • AUTxx talimatları authenticate + strip yapar (PAC’ı doğrula ve çıkar)
  • XPACxx talimatları strip yapar doğrulama olmadan

Domain / suffix’ler:

MnemonicMeaning / DomainKey / DomainExample Usage in Assembly
PACIASign instruction pointer with APIAKey“I, A”PACIA X0, X1 — sign pointer in X0 using APIAKey with modifier X1
PACIBSign instruction pointer with APIBKey“I, B”PACIB X2, X3
PACDASign data pointer with APDAKey“D, A”PACDA X4, X5
PACDBSign data pointer with APDBKey“D, B”PACDB X6, X7
PACG / PACGAGeneric (non-pointer) signing with APGAKey“G”PACGA X8, X9, X10 (sign X9 with modifier X10 into X8)
AUTIAAuthenticate APIA-signed instruction pointer & strip PAC“I, A”AUTIA X0, X1 — check PAC on X0 using modifier X1, then strip
AUTIBAuthenticate APIB domain“I, B”AUTIB X2, X3
AUTDAAuthenticate APDA-signed data pointer“D, A”AUTDA X4, X5
AUTDBAuthenticate APDB-signed data pointer“D, B”AUTDB X6, X7
AUTGAAuthenticate generic / blob (APGA)“G”AUTGA X8, X9, X10 (validate generic)
XPACIStrip PAC (instruction pointer, no validation)“I”XPACI X0 — remove PAC from X0 (instruction domain)
XPACDStrip PAC (data pointer, no validation)“D”XPACD X4 — remove PAC from data pointer in X4

Bazı uzmanlaşmış / alias formları vardır:

  • PACIASP PACIA X30, SP için kısa yazımdır (link register’ı SP ile modifier kullanarak imzala)
  • AUTIASP AUTIA X30, SP’dir (link register’ı SP ile doğrula)
  • RETAA, RETAB (authenticate-and-return) veya BLRAA (authenticate & branch) gibi birleşik formlar ARM uzantılarında / derleyici desteğinde bulunur.
  • Ayrıca modifier’ın sıfır olduğu varyantlar: PACIZA / PACIZB gibi, modifier implisit sıfırdır.

Modifiers

Modifier’ın ana hedefi PAC’ı belirli bir bağlama bağlamaktır; böylece aynı adres farklı bağlamlarda farklı PAC üretir. Bu, pointer yeniden kullanımını farklı stack frame’leri veya objeler arasında zorlaştırır. Tuz (salt) eklemeye benzer.

Buna göre:

  • Modifier bir bağlam değeri (başka bir register) olup PAC hesaplamasına karıştırılır. Tipik tercihler: stack pointer (SP), frame pointer veya bir obje ID’si.
  • SP’in modifier olarak kullanılması return address signing için yaygındır: PAC belirli stack frame’e bağlanır. LR’ı farklı bir frame’de yeniden kullanmaya çalışırsanız modifier değişir ve PAC doğrulaması başarısız olur.
  • Aynı pointer değeri farklı modifier’larla imzalandığında farklı PAC’lar ortaya çıkar.
  • Modifier gizli olmak zorunda değildir, ancak ideal olarak saldırgan tarafından kontrol edilmemiş olmalıdır.
  • Hiçbir anlamlı modifier’ın olmadığı durumlarda bazı formlar sıfır veya implisit sabit kullanır.

Apple / iOS / XNU Customizations & Observations

  • Apple’ın PAC uygulaması per-boot diversifier içerir; böylece anahtarlar veya tweak’ler her boot’ta değişir ve boot’lar arasında yeniden kullanım önlenir.
  • Ayrıca cross-domain mitigations içerir; user modunda imzalanan PAC’ların kolayca kernel modunda yeniden kullanılmasını zorlaştırır.
  • Apple Silicon (M1) üzerinde tersine mühendislikle, Apple’ın dokuz modifier tipi ve anahtar kontrolü için Apple-özgü sistem register’ları kullandığı görüldü.
  • Apple PAC’ı birçok kernel alt sisteminde kullanır: return address signing, kernel verilerinde pointer integritesi, signed thread context’leri vb.
  • Google Project Zero, güçlü bir memory read/write primitive ile kernel PAC’larını (A anahtarları için) sahteleyebilecek yollar gösterdi (A12-era) ancak Apple birçok yolu patched etti.
  • Apple’ın sisteminde bazı anahtarlar kernel çapında global, bazıları ise user process’lere per-process key randomness sağlar.

PAC Bypasses

  1. Kernel-mode PAC: theoretical vs real bypasses
  • Kernel PAC anahtarları ve mantığı sıkı kontrol edildiği için (ayrıcalıklı register’lar, diversifier’lar, domain izolasyonu) arbitrary imzalı kernel pointer’ları sahtelemek çok zordur.
  • Azad’ın 2020 “iOS Kernel PAC, One Year Later” raporu iOS 12-13’te birkaç kısmi bypass (signing gadgets, reuse of signed states, unprotected indirect branches) bulduğunu rapor etti ama genel bir bypass bulunmadı. bazad.github.io
  • Apple’ın “Dark Magic” özelleştirmeleri de saldırılabilir yüzeyleri (domain switching, per-key enabling bits) daralttı. i.blackhat.com
  • Apple silicon (M1/M2) için Zecao Cai ve ekibinin bildirdiği bilinen bir kernel PAC bypass CVE-2023-32424 vardır. i.blackhat.com
  • Ancak bu bypass’lar genellikle çok spesifik gadget’lara veya uygulama hatalarına dayanır; genel amaçlı bir bypass değillerdir.

Dolayısıyla kernel PAC yüksek düzeyde robust kabul edilir, ama kusursuz değildir.

  1. User-mode / runtime PAC bypass techniques

Bunlar daha yaygındır ve PAC’ın dinamik bağlayıcı/çalışma zamanı çerçevelerinde nasıl uygulandığındaki eksiklikleri suistimal eder. Aşağıda sınıflar ve örnekler var.

2.1 Shared Cache / A key issues

  • dyld shared cache, sistem framework’leri ve kütüphanelerin büyük ön-linklenmiş bir blob’udur. Bu kadar yaygın paylaşıldığı için shared cache içindeki function pointer’lar “önceden imzalanmış” olur ve birçok süreç tarafından kullanılır. Saldırganlar bu zaten-imzalanmış pointer’ları “PAC oracle” olarak hedef alır.
  • Bazı bypass teknikleri shared cache’de bulunan A-key ile imzalanmış pointer’ları çıkarıp reuse etmeye çalışır.
  • “No Clicks Required” konuşması, shared cache üzerinde bir oracle inşa ederek relatif adresleri çıkarmayı ve imzalı pointer’larla birleştirerek PAC’ı atlatmayı anlattı. saelo.github.io
  • Ayrıca userspace’deki shared library import’ları tarafından getirilen function pointer’ların PAC ile yeterince korunmadığı ve saldırganın imzayı değiştirmeden pointer elde edebildiği durumlar bulundu. (Project Zero bug entry) bugs.chromium.org

2.2 dlsym(3) / dynamic symbol resolution

  • Bilinen bir bypass dlsym() çağırıp zaten imzalanmış bir function pointer almak ve onu kullanmaktır (A-key ile, diversifier sıfır ile imzalanmış). Çünkü dlsym meşru olarak imzalanmış bir pointer döndürür, bu da PAC sahteleme ihtiyacını ortadan kaldırır.
  • Epsilon’ın blogu bazı bypass’ların bunu nasıl kullandığını detaylandırır: dlsym("someSym") çağrısı imzalı bir pointer döndürür ve indirect call’lar için kullanılabilir. blog.epsilon-sec.com
  • Synacktiv’in “iOS 18.4 — dlsym considered harmful” yazısı bir bug’ı anlatır: iOS 18.4’te dlsym ile çözülen bazı semboller yanlış imzalanmış veya hatalı diversifier ile dönüyor, bu da beklenmeyen PAC bypass’a yol açıyor. Synacktiv
  • dyld’deki logic: result->isCode olduğunda döndürülen pointer’ı __builtin_ptrauth_sign_unauthenticated(..., key_asia, 0) ile sign ediyorlar, yani bağlam sıfır. blog.epsilon-sec.com

Bu yüzden dlsym user-mode PAC bypass’larında sık kullanılan bir vektördür.

2.3 Other DYLD / runtime relocations

  • DYLD loader ve dynamic relocation mantığı karmaşıktır ve bazen relocasyon yapmak için sayfaları geçici olarak read/write map’ler, sonra tekrar read-only yapar. Saldırganlar bu pencereyi suistimal eder. Synacktiv’in konuşması “Operation Triangulation” adında zamanlama tabanlı bir PAC bypass’ını anlatır (dynamic relocations aracılığıyla). Synacktiv
  • DYLD sayfaları artık SPRR / VM_FLAGS_TPRO ile korunuyor (dyld için bazı koruma flag’leri). Ancak önceki sürümlerde daha zayıf korumalar vardı. Synacktiv
  • WebKit exploit zincirlerinde DYLD loader genellikle PAC bypass için hedeflenir. Slaytlar birçok PAC bypass’ın DYLD loader’ı (relocation, interposer hook’lar aracılığıyla) hedef aldığını not eder. Synacktiv

2.4 NSPredicate / NSExpression / ObjC / SLOP

  • Userland exploit zincirlerinde Objective-C runtime yöntemleri (NSPredicate, NSExpression, NSInvocation) kontrol çağrılarını gizlice taşımak için kullanılır.
  • PAC öncesi eski iOS’ta bir exploit fake NSInvocation objeleriyle kontrolü elden geçiriyordu. PAC ile teknik değişiklik gerektirdi, ama SLOP (SeLector Oriented Programming) yöntemi PAC altında da genişletildi. Project Zero
  • Orijinal SLOP tekniği, fake invocation’lar oluşturarak ObjC çağrılarının zincirlenmesine izin veriyordu; bypass, ISA veya selector pointer’larının bazen tam olarak PAC ile korunmamasına dayanıyordu. Project Zero
  • Pointer authentication kısmen uygulandığı ortamlarda, bazı methodlar / selector’lar / target pointer’lar her zaman PAC korumasına sahip olmayabilir, bu da bypass için fırsat bırakır.

Example Flow

Example Signing & Authenticating ``` ; Example: function prologue / return address protection my_func: stp x29, x30, [sp, #-0x20]! ; push frame pointer + LR mov x29, sp PACIASP ; sign LR (x30) using SP as modifier ; … body … mov sp, x29 ldp x29, x30, [sp], #0x20 ; restore AUTIASP ; authenticate & strip PAC ret

; Example: indirect function pointer stored in a struct ; suppose X1 contains a function pointer PACDA X1, X2 ; sign data pointer X1 with context X2 STR X1, [X0] ; store signed pointer

; later retrieval: LDR X1, [X0] AUTDA X1, X2 ; authenticate & strip BLR X1 ; branch to valid target

; Example: stripping for comparison (unsafe) LDR X1, [X0] XPACI X1 ; strip PAC (instruction domain) CMP X1, #some_label_address BEQ matched_label

</details>

<details>
<summary>Örnek</summary>
A buffer overflow, stack üzerindeki bir return adresini ezerek çalışır. Saldırgan hedef gadget adresini yazar ama doğru PAC'ı hesaplayamaz. Fonksiyon döndüğünde, CPU’nun `AUTIA` talimatı PAC uyuşmazlığı nedeniyle hata verir. Zincir başarısız olur.
Project Zero’nun A12 (iPhone XS) üzerine analizi, Apple’ın PAC kullanımını ve bir saldırganın memory read/write primitive’a sahip olması durumunda PAC’ları nasıl sahteleyebileceğini gösterdi.
</details>


### 9. **Branch Target Identification (BTI)**
**ARMv8.5 ile tanıtıldı (daha yeni donanım)**
BTI, **indirect branch target'ları** kontrol eden bir donanım özelliğidir: `blr` veya dolaylı call/jump'lar yürütülürken, hedef bir **BTI landing pad** (`BTI j` veya `BTI c`) ile başlamalıdır. Landing pad içermeyen gadget adreslerine atlamak bir istisna tetikler.

LLVM’nin uygulama notları BTI talimatlarının üç varyantını ve bunların branch türleriyle nasıl eşlendiğini not eder.

| BTI Variant | Hangi şeylere izin verir (hangi branch türleri) | Tipik yerleştirme / kullanım |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | *call*-stil dolaylı branch hedefleri (ör. `BLR`, veya X16/X17 kullanılarak `BR`) | Dolaylı olarak çağrılabilecek fonksiyonların girişine konur |
| **BTI J** | *jump*-stil branch hedefleri (ör. tail call için kullanılan `BR`) | jump tablolarından veya tail-call'larla ulaşılabilen blokların başına konur |
| **BTI JC** | Hem C hem J gibi davranır | Hem call hem jump branch'leri tarafından hedef alınabilir |

- Branch target enforcement ile derlenen kodda, derleyiciler her geçerli indirect-branch hedefinde (fonksiyon başlangıçları veya jump ile erişilebilen bloklar) bir BTI talimatı (C, J veya JC) ekler, böylece dolaylı branch'lar sadece bu yerlere başarılı şekilde gidebilir.
- **Direct branches / calls** (yani sabit adresli `B`, `BL`) BTI tarafından **kısıtlanmaz**. Varsayım şudur: kod sayfaları güvenilirdir ve saldırgan bunları değiştiremez (dolayısıyla direct branch'ler güvenlidir).
- Ayrıca, **RET / return** talimatları genelde BTI ile kısıtlanmaz çünkü dönüş adresleri PAC veya return signing mekanizmalarıyla korunur.

#### Mekanizma ve uygulama

- CPU, bir sayfa “guarded / BTI-enabled” olarak işaretlenmişken bir **indirect branch (BLR / BR)** decode ettiğinde, hedef adresin ilk talimatının geçerli bir BTI (izin verilen C, J veya JC) olup olmadığını kontrol eder. Değilse bir **Branch Target Exception** oluşur.
- BTI talimatı kodlaması, daha önce NOPs için ayrılmış opcode’ları yeniden kullanacak şekilde tasarlanmıştır (önceki ARM versiyonlarında). Bu nedenle BTI-etkin ikili dosyalar geriye dönük uyumludur: BTI desteklemeyen donanımda bu talimatlar NOP gibi davranır.
- BTI ekleyen derleyici pass’ları yalnızca ihtiyaç olan yerlere yerleştirir: dolaylı olarak çağrılabilecek fonksiyonlar veya jump'larla hedeflenen basic block'lar.
- Bazı yamalar ve LLVM kodu gösteriyor ki BTI tüm basic block'lar için eklenmez — sadece potansiyel branch hedefleri olanlar için (ör. switch / jump tablolarından gelenler).

#### BTI + PAC sinerjisi

PAC, pointer değerini (kaynağı) korur — dolaylı çağrıların/dönüşlerin zincirinin değiştirilmediğini garanti eder.

BTI, geçerli bir pointer olsa bile hedefin yalnızca doğru işaretlenmiş giriş noktalarına işaret etmesi gerektiğini sağlar.

Birlikte, bir saldırganın hem doğru PAC'a sahip geçerli bir pointer hem de hedefte BTI bulunması gerekir. Bu, exploit gadget’ları oluşturmayı zorlaştırır.

#### Örnek


<details>
<summary>Örnek</summary>
Bir exploit, `0xABCDEF` adresindeki ve `BTI c` ile başlamayan bir gadget'a pivot etmeye çalışır. CPU, `blr x0` yürütüldüğünde hedefi kontrol eder ve talimat hizalaması geçerli bir landing pad içermediği için hata verir. Böylece birçok gadget, BTI öneki içermedikçe kullanılamaz hale gelir.
</details>


### 10. **Privileged Access Never (PAN) & Privileged Execute Never (PXN)**
**Daha yeni ARMv8 uzantılarında / iOS desteğinde tanıtıldı (sertleştirilmiş kernel için)**

#### PAN (Privileged Access Never)

- **PAN**, **ARMv8.1-A** ile tanıtılan ve **privileged code** (EL1 veya EL2) tarafından **user-accessible (EL0)** olarak işaretlenmiş belleğin **okunmasını veya yazılmasını** engelleyen bir özelliktir; PAN açık değilse bu erişime izin verilir.
- Fikir: kernel kandırılsa veya ele geçirilse bile, user-space pointer’larını rastgele dereference edemez; önce PAN'ı *temizlemelidir*, böylece `ret2usr` tarzı exploit veya user-kontrolündeki buffer'ların kötüye kullanımı riski azalır.
- PAN etkin olduğunda (PSTATE.PAN = 1), “EL0 tarafından erişilebilir” olarak işaretlenmiş sanal adreslere yapılan herhangi bir privileged load/store talimatı bir **permission fault** tetikler.
- Kernel, meşru olarak user-space belleğine erişmesi gerektiğinde (ör. user buffer'lara veri kopyalama), PAN'ı **geçici olarak devre dışı bırakmalı** (veya “unprivileged load/store” talimatlarını kullanmalı) ki bu erişime izin versin.
- Linux on ARM64'te PAN desteği yaklaşık 2015 civarında eklendi: kernel yamaları bu özelliği algılayıp `get_user` / `put_user` gibi çağrıları PAN'ı temizleyen varyantlarla değiştirdi.

**Önemli nüans / sınırlama / bug**
- Siguza ve diğerleri tarafından belirtildiği gibi, ARM tasarımındaki bir spesifikasyon hatası (veya belirsiz davranış), **execute-only user mappings** (`--x`) için PAN'ın **tetiklenmemesine** yol açabilir. Başka bir deyişle, bir user sayfası sadece yürütülebilir ve okuma izni yoksa, kernel’in okuma denemesi PAN tarafından engellenmeyebilir çünkü mimari “EL0 tarafından erişilebilir”i okunabilir izin gerektiriyor, sadece yürütülebilir olmasını değil. Bu, belirli konfigürasyonlarda PAN bypass'ına yol açar.
- Bu yüzden, eğer iOS / XNU execute-only user sayfalarına izin veriyorsa (ör. bazı JIT veya code-cache düzenlemeleri gibi), kernel PAN etkin olsa bile bu sayfalardan yanlışlıkla okuma yapabilir. Bu, ARMv8+ sistemlerde bilinen ince bir kullanılabilir alan.

#### PXN (Privileged eXecute Never)

- **PXN**, page table girdilerinde (leaf veya block entry'lerde) bulunan bir bayraktır ve sayfanın **privileged modda yürütülemeyeceğini** (ör. EL1 yürütürken) belirtir.
- PXN, kernel’in (veya herhangi bir privileged kodun) kontrolü tamamen ele geçirilse bile user-space sayfalarından talimat yürütmesini engeller. Özetle, kernel seviyesinde kontrol akışının user belleğine yönlendirilmesini durdurur.
- PAN ile birlikte şunu sağlar:
1. Kernel varsayılan olarak user veri sayfalarını okuyamaz/yazamaz (PAN)
2. Kernel user kodunu çalıştıramaz (PXN)
- ARMv8 page table formatında, leaf entry’lerin attribute bitleri içinde bir `PXN` biti (ve ayrıca unprivileged için `UXN`) bulunur.

Dolayısıyla kernel’in bozuk bir function pointer ile user belleğine yönelmesi durumunda, PXN biti bir hata tetikleyecektir.

#### Bellek-izin modeli & PAN ve PXN’in page table bitlerine eşlenmesi

PAN / PXN’in nasıl çalıştığını anlamak için ARM’ın translation ve izin modelinin nasıl çalıştığını (basitleştirilmiş) görmek gerekir:

- Her sayfa veya block entry’si, read/write ve privileged vs unprivileged için **AP[2:1]** ve yürütmeyi engelleme için **UXN / PXN** bitleri gibi attribute alanlarına sahiptir.
- PSTATE.PAN 1 olduğunda, donanım değişmiş semantikleri uygular: EL0 tarafından erişilebilir olarak işaretlenmiş sayfalara privileged erişimler engellenir (fault).
- Bahsedilen bug nedeniyle, yalnızca yürütülebilir (okunamaz) olarak işaretlenmiş sayfalar bazı implementasyonlarda “EL0 tarafından erişilebilir” olarak sayılmayabilir, dolayısıyla PAN atlatılabilir.
- Bir sayfanın PXN biti set edilmişse, talimat fetch’i daha yüksek ayrıcalık seviyesinden gelse bile yürütme yasaklanır.

#### Sertleştirilmiş bir OS (ör. iOS / XNU) içinde PAN / PXN’in kernel kullanımına dair

Sertleştirilmiş bir kernel tasarımında (Apple’ın kullanabileceği şekilde):

- Kernel varsayılan olarak PAN’ı etkinleştirir (böylece privileged kod kısıtlanır).
- Meşru olarak user buffer’larına erişmesi gereken yollar (ör. syscall buffer copy, I/O, user pointer ile read/write), kernel PAN’ı geçici olarak **devre dışı bırakır** veya user belleğe erişimi aşan özel talimatlar kullanır.
- User veri erişimi tamamlandıktan sonra PAN tekrar etkinleştirilmelidir.
- PXN page table aracılığıyla uygulanır: user sayfalarının PXN = 1 olarak ayarlanması (böylece kernel bunlarda yürütme yapamaz), kernel sayfalarının PXN’si 0 olur (kernel kodu yürütülebilir).
- Kernel, kontrol akışının user bellek bölgelerine yol açmayacağından emin olmalıdır — aksi halde “user-kontrolündeki shellcode’a atlama” gibi exploit zincirleri engellenemez.

Execute-only sayfalar üzerinden PAN atlatması nedeniyle, gerçek bir sistemde Apple execute-only user sayfalarını devre dışı bırakabilir veya spesifikasyon zayıflığına yönelik yamalar uygulayabilir.

#### Saldırı yüzeyleri, bypass'lar ve hafifletmeler

- **Execute-only sayfalar yoluyla PAN bypass**: yukarıda tartışıldığı gibi, spesifikasyon bir boşluk bırakır: okuma izni olmayan sadece yürütülebilir user sayfaları bazı implementasyonlarda “EL0 tarafından erişilebilir” sayılmayabilir; böylece PAN kernel okumasını engellemez. Bu, saldırganın “execute-only” bölümler aracılığıyla veri beslemesine izin verebilir.
- **Zamana dayalı pencere exploit'i**: kernel PAN'ı gerekenden uzun süre devre dışı bırakırsa, bir yarış veya kötü niyetli yol bu pencereyi kullanarak istenmeyen user bellek erişimleri gerçekleştirebilir.
- **Yeniden etkinleştirmeyi unutma**: eğer kod yolları PAN'ı tekrar etkinleştirmeyi unutursa, sonraki kernel işlemleri yanlışlıkla user belleğe erişebilir.
- **PXN yanlış yapılandırması**: page table'lar user sayfalarında PXN'yi ayarlamazsa veya user kod sayfalarını hatalı şekilde map ederse, kernel user-space kodunu çalıştırmaya ikna edilebilir.
- **Spekülasyon / yan-kanallar**: spekülatif atlamalara benzer şekilde, mikro-mimari yan-etkiler PAN / PXN kontrollerinin geçici olarak ihlal edilmesine sebep olabilir (ancak bu tür saldırılar CPU tasarımına çok bağımlıdır).
- **Karmaşık etkileşimler**: JIT, shared memory, just-in-time code bölgeleri gibi gelişmiş özelliklerde kernel, user-mapped bölgeler için belirli erişimlere izin vermek zorunda olabilir; PAN/PXN kısıtları altında bunları güvenli şekilde tasarlamak karmaşıktır.

#### Örnek

<details>
<summary>Code Example</summary>
Here are illustrative pseudo-assembly sequences showing enabling/disabling PAN around user memory access, and how a fault might occur.
</details>

// Suppose kernel entry point, PAN is enabled (privileged code cannot access user memory by default)

; Kernel receives a syscall with user pointer in X0 ; wants to read an integer from user space mov X1, X0 ; X1 = user pointer

; disable PAN to allow privileged access to user memory MSR PSTATE.PAN, #0 ; clear PAN bit, disabling the restriction

ldr W2, [X1] ; now allowed load from user address

; re-enable PAN before doing other kernel logic MSR PSTATE.PAN, #1 ; set PAN

; … further kernel work …

; Later, suppose an exploit corrupts a pointer to a user-space code page and jumps there BR X3 ; branch to X3 (which points into user memory)

; Because the target page is marked PXN = 1 for privileged execution, ; the CPU throws an exception (fault) and rejects execution

Eğer kernel o kullanıcı sayfasında PXN'i **ayarlamamış** olsaydı, o branch başarılı olabilir — ki bu güvensiz olurdu.

Kernel kullanıcı bellek erişiminden sonra PAN'i yeniden etkinleştirmeyi unutursa, ilerideki kernel mantığının istemeden rastgele kullanıcı belleğini okuma/yazma yapabileceği bir pencere açar.

Eğer kullanıcı işaretçisi execute-only bir sayfaya (sadece yürütme izni olan, okuma/yazma olmayan kullanıcı sayfası) işaret ediyorsa, PAN spesifikasyon hatası altında, `ldr W2, [X1]` PAN etkin olsa bile **hata vermeyebilir**, uygulamaya bağlı olarak bir atlatma (bypass) istismarına olanak sağlayabilir.

</details>

<details>
<summary>Example</summary>
Bir kernel açığı, kullanıcı tarafından sağlanan bir fonksiyon işaretçisini alıp kernel bağlamında çağırmaya çalışır (yani `call user_buffer`). PAN/PXN altında, bu işlem yasaklanır veya hata verir.
</details>

---

### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**ARMv8.5 ve sonrası (veya isteğe bağlı uzantı) üzerine tanıtıldı**
TBI, 64-bit bir işaretçinin en yüksek baytının adres çevirme tarafından yok sayılmasını sağlar. Bu sayede OS veya donanım, işaretçinin üst baytına **tag bitleri** gömebilir ve gerçek adresi etkilemez.

- TBI, **Top Byte Ignore** (bazen *Address Tagging* olarak da anılır) anlamına gelir. Bu, birçok ARMv8+ uygulamasında bulunan bir donanım özelliğidir ve 64-bit bir işaretçinin en üst 8 bitini (bits 63:56) **adres çevirme / load/store / instruction fetch** sırasında yok sayar.
- Pratikte CPU, `0xTTxxxx_xxxx_xxxx` (burada `TT` = üst bayt) biçimindeki bir işaretçiyi adres çevirme açısından `0x00xxxx_xxxx_xxxx` olarak ele alır; üst bayt maskelenir (strip edilir). Üst bayt yazılım tarafından **metadata / tag bitleri** saklamak için kullanılabilir.
- Bu, her işaretçiye bir byte’lık etiket gömmek için yazılıma “ücretsiz” bir kanal sağlar; bu işlem bellek lokasyonunu değiştirmez.
- Mimari, load/store ve instruction fetch işlemlerinin, gerçek bellek erişimi yapılmadan önce işaretçinin üst baytını maskelenmiş (yani tag çıkarılmış) şekilde işlemesini garanti eder.

Böylece TBI, **mantıksal işaretçi**yi (işaretçi + tag) bellek işlemlerinde kullanılan **fiziksel adresten** ayırır.

#### Why TBI: Use cases and motivation

- **Pointer tagging / metadata**: Üst baytta ek metadata (ör. obje tipi, versiyon, bounds, bütünlük tagleri) saklayabilirsiniz. İşaretçiyi daha sonra kullandığınızda, donanım düzeyinde tag görmezden gelindiği için bellek erişimi için elle strip etmenize gerek kalmaz.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI, MTE’nin üzerine inşa olduğu temel donanım mekanizmasıdır. ARMv8.5’te, **Memory Tagging Extension** işaretçinin bits 59:56'sını bir **mantıksal tag** olarak kullanır ve bunu bellekte saklanan bir **allocation tag** ile karşılaştırır.
- **Geliştirilmiş güvenlik & bütünlük**: TBI'yi pointer authentication (PAC) veya çalışma zamanı kontrolleri ile birleştirerek, sadece işaretçi değerinin değil aynı zamanda tagin de doğru olmasını zorlayabilirsiniz. Bir saldırgan işaretçiyi doğru tag olmadan üzerine yazar ise tag uyuşmazlığı oluşur.
- **Uyumluluk**: TBI isteğe bağlıdır ve tag bitleri donanım tarafından yok sayıldığı için, mevcut tag içermeyen kod normal şekilde çalışmaya devam eder. Tag bitleri eski kod için etkili olarak “önemsiz” bitler olur.

#### Example
<details>
<summary>Example</summary>
Bir fonksiyon işaretçisi üst baytına bir tag (ör. `0xAA`) içeriyordu. Bir exploit işaretçinin düşük bitlerini ezdi ama tagi gözardı etti; kernel doğrulama veya temizleme yaptığında işaretçi başarısız olur veya reddedilir.
</details>

---

### 12. **Page Protection Layer (PPL)**
**Geç dönem iOS / modern donanımda tanıtıldı (iOS ~17 / Apple silicon / üst seviye modeller)** (bazı raporlar PPL’yi macOS / Apple silicon civarında gösterse de, Apple benzer korumaları iOS’a da getiriyor)

- PPL, bir **kernel içi koruma sınırı** olarak tasarlandı: kernel (EL1) ele geçirilmiş ve okuma/yazma yetkisine sahip olsa bile, **belirli hassas sayfaları serbestçe değiştirememesi** gerekir (özellikle page table'lar, code-signing metadata, kernel kod sayfaları, entitlements, trust cache'ler vb.).
- Pratikte bir **“kernel içinde kernel”** yaratır — korunan sayfaları sadece değiştirebilen daha küçük, güvenilir bir bileşen (PPL) vardır. Diğer kernel kodu değişiklik yapmak için PPL rutinlerini çağırmak zorundadır.
- Bu, kernel exploitleri için saldırı yüzeyini azaltır: kernel modunda tam rastgele R/W/execute elde edilmiş olsa bile, saldırgan kritik yapıların değiştirilmesi için ya PPL alanına girmeli ya da PPL’i atlatmalıdır.
- Yeni Apple silicon (A15+ / M2+) üzerinde Apple, birçok durumda sayfa tablosu koruması için PPL’nin yerine **SPTM (Secure Page Table Monitor)** getirmeye geçiş yapıyor.

Aşağıda PPL’in kamuya açık analizlere dayanarak nasıl çalıştığına ilişkin inanışlar yer almaktadır:

#### Use of APRR / permission routing (APRR = Access Permission ReRouting)

- Apple donanımı, page table entry’lerin (PTE) tam izin bitleri yerine küçük indeksler içermesine izin veren **APRR (Access Permission ReRouting)** adlı bir mekanizma kullanır. Bu indeksler APRR registerları aracılığıyla gerçek izne eşlenir. Bu, domain başına izinlerin dinamik olarak yeniden eşlenmesine izin verir.
- PPL, APRR’yi kernel bağlamı içinde ayrıcalıkları ayırmak için kullanır: yalnızca PPL domaini, indeksler ile efektif izinler arasındaki eşlemeyi güncelleyebilir. Yani non-PPL kernel kodu bir PTE yazdığında veya izin bitlerini çevirmeye çalıştığında, APRR mantığı bunu engeller (veya salt okunur eşleme uygular).
- PPL kodu kendisi kısıtlı bir bölgede (ör. `__PPLTEXT`) çalışır; bu bölge normalde giriş kapıları geçici olarak izin verene kadar yürütülebilir veya yazılabilir değildir. Kernel, hassas işlemleri gerçekleştirmek için PPL entry noktalarını (“PPL rutinleri”) çağırır.

#### Gate / Entry & Exit

- Kernel korunan bir sayfayı değiştirmesi gerektiğinde (ör. bir kernel kod sayfasının izinlerini değiştirmek veya page table’ları değiştirmek), doğrulama yapan ve PPL alanına geçiş yapan bir **PPL wrapper** rutinini çağırır. Bu alanın dışında korunan sayfalar esasen ana kernel tarafından değiştirilemez veya yazılamaz.
- PPL girişinde, APRR eşlemeleri PPL bölgesindeki bellek sayfalarının PPL içinde **executable & writable** olacak şekilde ayarlanır. Çıkışta ise tekrar salt okunur / yazılamaz hale getirilir. Bu, yalnızca iyi denetlenmiş PPL rutinlerinin korunan sayfalara yazmasına izin verir.
- PPL dışındayken, kernel kodunun bu korunan sayfalara yazma girişimleri hata verir (izin reddedildi) çünkü o kod domaini için APRR eşlemesi yazma izni tanımaz.

#### Protected page categories

PPL’in tipik olarak koruduğu sayfalar şunlardır:

- Page table yapıları (translation table entries, mapping metadata)
- Kernel kod sayfaları, özellikle kritik mantığı içerenler
- Code-sign metadata (trust cache’ler, signature blob’ları)
- Entitlement tabloları, signature enforcement tabloları
- İmzalama kontrollerini atlamaya veya kimlik bilgilerini manipüle etmeye izin verecek diğer yüksek değerli kernel yapıları

Fikir şudur: kernel belleği tam kontrol altında olsa bile, saldırgan bu sayfaları basitçe patchleyemez veya yeniden yazamaz; bunu yapabilmek için ya PPL rutinlerini ele geçirmeleri ya da PPL’i atlatmaları gerekir.


#### Known Bypasses & Vulnerabilities

1. **Project Zero’s PPL bypass (stale TLB trick)**

- Project Zero tarafından yayımlanan bir yazıda **stale TLB entry’leri** içeren bir bypass anlatılmaktadır.
- Fikir:

1. İki fiziksel sayfa A ve B ayırın, bunları PPL sayfaları olarak işaretleyin (yani korumalı yapın).
2. L3 translation table sayfaları A ve B’den gelen iki sanal adres P ve Q mapleyin.
3. Bir iş parçacığını Q’ya sürekli erişecek şekilde döndürün, böylece onun TLB girişi canlı kalsın.
4. `pmap_remove_options()` çağırın; bir hatadan dolayı kod P için başlayan mappingleri kaldırırken yanlışlıkla hem P hem Q için TTE’leri kaldırır, ama yalnızca P’nin TLB girdisini invalide eder; Q’nunki stale (eski) olarak canlı kalır.
5. B’yi (Q’nin tablosu olan sayfayı) yeniden kullanarak rastgele belleği mapleyin (ör. PPL korumalı sayfalar). Çünkü stale TLB girişi hâlâ Q’nun eski mappingini o bağlam için geçerli gösterir.
6. Böylece saldırgan, PPL arayüzünden geçmeden PPL korumalı sayfaların yazılabilir mappingini yerleştirebilir.

- Bu exploit fiziksel mapping ve TLB davranışı üzerinde hassas kontrol gerektirmiştir. Bir güvenlik sınırının TLB / mapping tutarlılığına dayandığında, TLB invalidasyonları ve mapping tutarlılığı konusunda çok dikkatli olması gerektiğini gösterir.

- Project Zero, bu tür bypassların ince ve nadir olduğunu fakat karmaşık sistemlerde mümkün olduğunu belirtmiştir. Yine de PPL’i sağlam bir mitigasyon olarak değerlendirmişlerdir.

2. **Other potential hazards & constraints**

- Eğer bir kernel exploit doğrudan PPL rutinlerine girebiliyorsa (PPL wrapper’larını çağırarak), kısıtlamaları atlayabilir. Bu yüzden argüman doğrulaması kritik önemdedir.
- PPL kodunun kendisindeki hatalar (ör. aritmetik taşma, sınır kontrolleri) PPL içinde batasız değişikliklere izin verebilir. Project Zero, `pmap_remove_options_internal()` içindeki böyle bir hatanın bypass’ta kullanıldığını gözlemlemiştir.
- PPL sınırı donanım uygulamasına (APRR, memory controller) sıkı sıkıya bağlıdır; bu nedenle yalnızca donanım uygulaması kadar güçlüdür.



#### Example
<details>
<summary>Code Example</summary>
Burada, bir kernel’in korunan sayfaları değiştirmek için PPL’ye nasıl çağrı yapabileceğini gösteren basitleştirilmiş pseudocode / mantık gösterilmiştir:
</details>
```c
// In kernel (outside PPL domain)
function kernel_modify_pptable(pt_addr, new_entry) {
// validate arguments, etc.
return ppl_call_modify(pt_addr, new_entry)  // call PPL wrapper
}

// In PPL (trusted domain)
function ppl_call_modify(pt_addr, new_entry) {
// temporarily enable write access to protected pages (via APRR adjustments)
aprr_set_index_for_write(PPL_INDEX)
// perform the modification
*pt_addr = new_entry
// restore permissions (make pages read-only again)
aprr_restore_default()
return success
}

// If kernel code outside PPL does:
*pt_addr = new_entry  // a direct write
// It will fault because APRR mapping for non-PPL domain disallows write to that page

Kernel birçok normal işlemi gerçekleştirebilir, ancak korumalı eşlemeleri değiştirmek veya kodu yama yapmak yalnızca ppl_call_* rutinleri aracılığıyla mümkündür.

Örnek Bir kernel exploit'i entitlement tablosunu üzerine yazmaya çalışır veya bir kernel signature blob'u değiştirerek code-sign denetimini devre dışı bırakır. Çünkü o sayfa PPL tarafından korunur, yazma PPL arayüzü üzerinden yapılmadıkça engellenir. Yani kernel kodu çalıştırma imkanınız olsa bile code-sign kısıtlamalarını atlayamaz veya kimlik bilgisi verilerini rastgele değiştiremezsiniz. iOS 17+ üzerinde bazı cihazlar PPL tarafından yönetilen sayfaları daha da izole etmek için SPTM kullanır.

PPL → SPTM / Yerine Geçirme / Gelecek

  • Apple’ın modern SoC’larında (A15 veya daha yeni, M2 veya daha yeni), Apple SPTM (Secure Page Table Monitor) destekler; bu, sayfa tablosu korumaları için PPL’nin yerini alır.
  • Apple dokümantasyonda belirtir: “Page Protection Layer (PPL) and Secure Page Table Monitor (SPTM) enforce execution of signed and trusted code … PPL manages the page table permission overrides … Secure Page Table Monitor replaces PPL on supported platforms.”
  • SPTM mimarisi muhtemelen daha fazla politika uygulamasını kernel kontrolü dışındaki, daha yüksek ayrıcalıklı bir monitöre kaydırır ve böylece güven sınırını daha da küçültür.

MTE | EMTE | MIE

Apple’ın MIE kurulumu altında EMTE’nin nasıl çalıştığına dair daha üst düzey bir açıklama:

  1. Tag assignment
  • Bellek tahsis edildiğinde (ör. kernel veya kullanıcı alanında secure allocator’lar aracılığıyla), o blok için bir secret tag atanır.
  • Kullanıcıya veya kernele döndürülen pointer, yüksek bitlerinde o tag’i içerir (TBI / top byte ignore mekanizmaları kullanılarak).
  1. Tag checking on access
  • Bir pointer kullanılarak bir load veya store gerçekleştirildiğinde, donanım pointer’ın tag’inin bellek bloğunun tag’i (allocation tag) ile eşleşip eşleşmediğini kontrol eder. Uyuşmazlık varsa hemen fault oluşturur (çünkü synchronous).
  • Synchronous olduğu için “gecikmeli tespit” penceresi yoktur.
  1. Retagging on free / reuse
  • Bellek freedildiğinde, allocator bloğun tag’ini değiştirir (eski tag’e sahip pointer’lar artık eşleşmez).
  • Bu nedenle bir use-after-free pointer erişildiğinde stale bir tag’e sahip olur ve uyumsuzluk oluşur.
  1. Neighbor-tag differentiation to catch overflows
  • Bitişik tahsislere farklı tag’ler verilir. Eğer bir buffer overflow komşu belleğe taşarsa, tag uyumsuzluğu bir fault oluşturur.
  • Bu, sınırı geçen küçük overflow’ları yakalamada özellikle etkilidir.
  1. Tag confidentiality enforcement
  • Apple, tag değerlerinin leaked olmasını önlemelidir (çünkü saldırgan tag’i öğrenirse doğru tag’e sahip pointer’lar oluşturabilir).
  • Tag bitlerinin side-channel leak’ine karşı korunması için microarchitectural / speculative kontroller gibi korumalar dahil edilir.
  1. Kernel and user-space integration
  • Apple EMTE’yi sadece user-space’te değil, kernel / OS-kritik bileşenlerde de kullanır (kernele yönelik bellek bozulmalarına karşı korumak için).
  • Donanım/OS, kernel kullanıcı adına çalışıyor olsa bile tag kurallarının uygulanmasını garanti eder.
Örnek ``` Allocate A = 0x1000, assign tag T1 Allocate B = 0x2000, assign tag T2

// pointer P points into A with tag T1 P = (T1 << 56) | 0x1000

// Valid store *(P + offset) = value // tag T1 matches allocation → allowed

// Overflow attempt: P’ = P + size_of_A (into B region) *(P’ + delta) = value → pointer includes tag T1 but memory block has tag T2 → mismatch → fault

// Free A, allocator retags it to T3 free(A)

// Use-after-free: *(P) = value → pointer still has old tag T1, memory region is now T3 → mismatch → fault

</details>

#### Limitations & challenges

- **Intrablock overflows**: Eğer overflow aynı tahsis içinde kalırsa (sınırı geçmez) ve tag aynı kalırsa, tag mismatch bunu yakalamaz.
- **Tag width limitation**: Tag için sadece birkaç bit (örn. 4 bit veya küçük bir domain) mevcuttur—sınırlı isim alanı.
- **Side-channel leaks**: Eğer tag bitleri (cache / speculative execution üzerinden) leak olabiliyorsa, saldırgan geçerli tagleri öğrenip atlayabilir. Apple’ın tag confidentiality enforcement bu durumu hafifletmeyi amaçlar.
- **Performance overhead**: Her load/store için yapılan tag kontrolleri maliyet ekler; Apple donanımı optimize ederek overhead’i düşük tutmak zorunda.
- **Compatibility & fallback**: Eski donanım veya EMTE desteklemeyen parçalar için fallback olmalı. Apple, MIE’nin yalnızca destekli cihazlarda etkin olduğunu iddia ediyor.
- **Complex allocator logic**: Allocator tag’leri yönetmeli, retagging, hizalama sınırlarını ve çakışmaları önlemelidir. Allocator mantığındaki hatalar yeni güvenlik açıkları yaratabilir.
- **Mixed memory / hybrid areas**: Bazı bellekler untagged (legacy) kalabilir; bu, birlikte çalışabilirliği daha karmaşık hale getirir.
- **Speculative / transient attacks**: Birçok mikro-mimari korumada olduğu gibi, speculative execution veya micro-op füzyonları kontrolleri geçici olarak atlatabilir veya tag bitlerini leak edebilir.
- **Limited to supported regions**: Apple EMTE’yi yalnızca seçili, yüksek riskli alanlarda (kernel, güvenlik kritik alt sistemler) zorunlu kılabilir; evrensel olmayabilir.



---

## Key enhancements / differences compared to standard MTE

Here are the improvements and changes Apple emphasizes:

| Feature | Original MTE | EMTE (Apple’s enhanced) / MIE |
|---|---|---|
| **Check mode** | Senkron ve asenkron modları destekler. Asenkron modda, tag uyuşmazlıkları daha sonra (gecikmeli) bildirilir. | Apple varsayılan olarak **synchronous mode**’u zorunlu kılar—tag uyuşmazlıkları anında yakalanır, gecikme/yarış penceresi yoktur.|
| **Coverage of non-tagged memory** | non-tagged memory (örn. globals) erişimleri bazı uygulamalarda kontrolleri atlayabilir | EMTE, tag’li bir bölgeden non-tagged memory’ye yapılan erişimlerin de tag bilgisini doğrulamasını zorunlu kılar; böylece tahsisleri karıştırarak atlatmak zorlaşır.|
| **Tag confidentiality / secrecy** | Tags gözlemlenebilir veya leaked via side channels olabilir | Apple **Tag Confidentiality Enforcement** ekler; tag değerlerinin (via speculative side-channels vb.) sızdırılmasını/observation’u engellemeye çalışır.|
| **Allocator integration & retagging** | MTE büyük ölçüde allocator mantığını yazılıma bırakır | Apple’ın secure typed allocators (kalloc_type, xzone malloc, vb.) EMTE ile entegre olur: bellek allocate/	free edildiğinde tag’ler ince granulariteyle yönetilir.|
| **Always-on by default** | Birçok platformda MTE isteğe bağlıdır veya varsayılan kapalıdır | Apple, desteklenen donanımlarda (örn. iPhone 17 / A19) kernel ve birçok kullanıcı süreci için EMTE / MIE’yi varsayılan etkin olarak açar.|

Apple hem donanımı hem yazılım yığını kontrol ettiği için EMTE’yi sıkı şekilde uygulayabilir, performans tuzaklarından kaçınabilir ve side-channel açıklarını kapatabilir.

---

## How EMTE works in practice (Apple / MIE)

Here’s a higher-level description of how EMTE operates under Apple’s MIE setup:

1. **Tag assignment**
- Bellek allocate edildiğinde (örn. kernel veya kullanıcı alanında secure allocators ile), o blok için bir **secret tag** atanır.
- Kullanıcıya veya kernela döndürülen pointer, tag’i yüksek bitlerinde içerir (TBI / top byte ignore mekanizmalarını kullanarak).

2. **Tag checking on access**
- Bir pointer kullanılarak load veya store çalıştırıldığında donanım pointer’ın tag’inin bellek bloğunun tag’i (allocation tag) ile eşleşip eşleşmediğini kontrol eder. Mismatch olursa hemen fault verir (synchronous olduğu için).
- Senkron olduğu için “gecikmeli tespit” penceresi yoktur.

3. **Retagging on free / reuse**
- Bellek free edildiğinde allocator bloğun tag’ini değiştirir (eski pointer’ların tag’i artık geçerli olmaz).
- Bu sayede use-after-free pointer’ı stale tag’e sahip olur ve erişimde mismatch oluşur.

4. **Neighbor-tag differentiation to catch overflows**
- Bitişik allocation’lara farklı tag’ler verilir. Eğer bir buffer overflow komşu belleğe sıçrarsa, tag mismatch fault oluşturur.
- Bu, sınırı geçen küçük overflows’ları yakalamada özellikle etkilidir.

5. **Tag confidentiality enforcement**
- Apple, tag değerlerinin leak olmasını engellemelidir (çünkü saldırgan tag’i öğrenebilirse doğru tag’li pointer’lar oluşturabilir).
- Bu amaçla speculative side-channel’lara karşı mikro-mimari / spekülatif kontroller içerir.

6. **Kernel and user-space integration**
- Apple EMTE’yi yalnızca kullanıcı alanında değil, kernel / OS-kritik bileşenlerde de kullanır (kernel’i bellek bozulmalarına karşı korumak için).
- Donanım/OS, tag kurallarının kullanıcı adına kernel yürütülürken bile uygulanmasını sağlar.

EMTE, MIE içine entegre olduğundan Apple, kritik saldırı yüzeylerinde EMTE’yi senkron modda kullanır; bu bir debug/isteğe bağlı mod değildir.



---

## Exception handling in XNU

When an **exception** occurs (e.g., `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, etc.), the **Mach layer** of the XNU kernel is responsible for intercepting it before it becomes a UNIX-style **signal** (like `SIGSEGV`, `SIGBUS`, `SIGILL`, ...).

Bu süreç, kullanıcı alanına ulaşmadan veya BSD sinyaline dönüştürülmeden önce birden fazla istisna yayılma ve işleme katmanını içerir.


### Exception Flow (High-Level)

1.  **CPU triggers a synchronous exception** (örn. geçersiz pointer dereference, PAC failure, illegal instruction, vb.).

2.  **Low-level trap handler** çalışır (`trap.c`, `exception.c` içinde XNU kaynağı).

3.  Trap handler **`exception_triage()`**’yi çağırır; bu Mach exception handling’in merkezidir.

4.  `exception_triage()` istisnayı nasıl yönlendireceğine karar verir:

-   Önce **thread'in exception port**una.
-   Sonra **task'ın exception port**una.
-   Sonra **host'un exception port**una (genellikle `launchd` veya `ReportCrash`).

Eğer bu portların hiçbiri istisnayı ele almazsa, kernel:

-   **Bunu bir BSD sinyaline dönüştürebilir** (kullanıcı alanı süreçleri için).
-   **Panic** yapabilir (kernel alanı istisnaları için).


### Core Function: `exception_triage()`

`exception_triage()` fonksiyonu Mach istisnalarını zincir boyunca uygun handler’a kadar yönlendirir; bir handler ele alana kadar veya nihayetinde ölümcül olana kadar bu süreç devam eder. Fonksiyon `osfmk/kern/exception.c` içinde tanımlıdır.
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);

Tipik Çağrı Akışı:

exception_triage() └── exception_deliver() ├── exception_deliver_thread() ├── exception_deliver_task() └── exception_deliver_host()

Hepsi başarısız olursa → bsd_exception() tarafından işlenir → SIGSEGV gibi bir sinyale çevrilir.

İstisna Portları

Her Mach nesnesi (thread, task, host) istisna mesajlarının gönderildiği istisna portlarını kaydedebilir.

Bunlar API tarafından tanımlanır:

task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()

Her exception port’unun:

  • A mask (almak istediği exception’lar)
  • A port name (mesajları almak için Mach portu)
  • A behavior (kernel’in mesajı nasıl gönderdiği)
  • A flavor (hangi thread state’in dahil edileceği)

Debuggers and Exception Handling

Bir debugger (ör. LLDB) hedef task veya thread üzerinde genellikle task_set_exception_ports() kullanarak bir exception port ayarlar.

Bir exception oluştuğunda:

  • Mach mesajı debugger sürecine gönderilir.
  • Debugger exception’ı handle (resume, register’ları değiştir, instruction’ı atla) etmeye veya etmeme kararı verebilir.
  • Eğer debugger handle etmezse, exception bir sonraki seviyeye yayılır (task → host).

EXC_BAD_ACCESS Akışı

  1. Thread geçersiz bir pointer’ı dereference eder → CPU Data Abort tetikler.

  2. Kernel trap handler exception_triage(EXC_BAD_ACCESS, ...) çağırır.

  3. Mesaj şuraya gönderilir:

  • Thread port → (debugger breakpoint’ı yakalayabilir).

  • Eğer debugger gözardı ederse → Task port → (process-seviyesinde handler).

  • Eğer yine gözardı edilirse → Host port (genellikle ReportCrash).

  1. Kimse handle etmezse → bsd_exception() bunu SIGSEGV’e çevirir.

PAC Exceptions

Pointer Authentication (PAC) başarısız olduğunda (signature uyuşmazlığı), özel bir Mach exception yükseltilir:

  • EXC_ARM_PAC (tür)
  • Kodlar detaylar içerebilir (ör. key tipi, pointer tipi).

Eğer binary’de TFRO_PAC_EXC_FATAL flag’i varsa, kernel PAC hatalarını fatal olarak değerlendirir ve debugger intercept’ini atlar. Bu, saldırganların debugger kullanarak PAC kontrollerini atlatmasını engellemek içindir ve platform binaries için etkinleştirilmiştir.

Software Breakpoints

Bir software breakpoint (int3 on x86, brk on ARM64) kasıtlı bir fault oluşturularak uygulanır.
Debugger bunu exception port üzerinden yakalar:

  • Instruction pointer veya memory’i değiştirir.
  • Orijinal instruction’ı geri yükler.
  • Execution’ı devam ettirir.

Aynı mekanizma PAC exception’ı “yakalamanıza” izin verir — TFRO_PAC_EXC_FATAL ayarlı değilse ulaşır; aksi halde debugger’a hiç ulaşmaz.

Conversion to BSD Signals

Eğer hiçbir handler exception’ı kabul etmezse:

  • Kernel task_exception_notify() → bsd_exception() çağırır.

  • Bu Mach exception’ları signal’lara map eder:

Mach ExceptionSignal
EXC_BAD_ACCESSSIGSEGV or SIGBUS
EXC_BAD_INSTRUCTIONSIGILL
EXC_ARITHMETICSIGFPE
EXC_SOFTWARESIGTRAP
EXC_BREAKPOINTSIGTRAP
EXC_CRASHSIGKILL
EXC_ARM_PACSIGILL (on non-fatal)

### Key Files in XNU Source

  • osfmk/kern/exception.c → Core of exception_triage(), exception_deliver_*().

  • bsd/kern/kern_sig.c → Signal delivery logic.

  • osfmk/arm64/trap.c → Low-level trap handlers.

  • osfmk/mach/exc.h → Exception codes and structures.

  • osfmk/kern/task.c → Task exception port setup.


Old Kernel Heap (Pre-iOS 15 / Pre-A12 era)

Kernel, sabit boyutlu “zones” olarak bölünmüş bir zone allocator (kalloc) kullanıyordu.
Her zone yalnızca tek bir size class’taki allocation’ları tutardı.

Ekran görüntüsünden:

Zone NameElement SizeExample Use
default.kalloc.1616 bytesVery small kernel structs, pointers.
default.kalloc.3232 bytesSmall structs, object headers.
default.kalloc.6464 bytesIPC messages, tiny kernel buffers.
default.kalloc.128128 bytesMedium objects like parts of OSObject.
default.kalloc.12801280 bytesLarge structures, IOSurface/graphics metadata.

Nasıl çalışıyordu:

  • Her allocation isteği en yakın zone boyutuna yuvarlanır.
    (Ör. 50-byte isteği kalloc.64 zone’una düşer).
  • Her zone içindeki memory bir freelist içinde tutulurdu — kernel tarafından freed edilen chunk’lar yine o zone’a geri giderdi.
  • Eğer 64-byte buffer’ı taşırırsanız, aynı zone’daki bir sonraki objeyi overwrite ederdiniz.

Bu yüzden heap spraying / feng shui çok etkiliydi: aynı size class’ta allocation’lar spray ederek obje komşularını tahmin edebiliyordunuz.

The freelist

Her kalloc zone içinde, freed objeler doğrudan sisteme geri verilmez — bir freelist’e, yani kullanılabilir chunk’ların bağlı listesine giderdi.

  • Bir chunk free edildiğinde, kernel o chunk’ın başına bir pointer yazar → aynı zone’daki bir sonraki free chunk’ın adresi.

  • Zone ilk free chunk’ın HEAD pointer’ını tutardı.

  • Allocation her zaman mevcut HEAD’i kullanırdı:

  1. HEAD’i pop et (o belleği çağırana geri ver).

  2. HEAD = HEAD->next olarak güncelle (freed chunk’ın header’ında saklı).

  • Free etme push yapardı:

  • freed_chunk->next = HEAD

  • HEAD = freed_chunk

Yani freelist, freed belleğin kendisi içine kurulan bir linked list’ti.

Normal durum:

Zone page (64-byte chunks for example):
[ A ] [ F ] [ F ] [ A ] [ F ] [ A ] [ F ]

Freelist view:
HEAD ──► [ F ] ──► [ F ] ──► [ F ] ──► [ F ] ──► NULL
(next ptrs stored at start of freed chunks)

freelist’i istismar etme

Çünkü bir free chunk’ın ilk 8 baytı = freelist pointer olduğundan, bir saldırgan bunu bozabilir:

  1. Heap overflow ile bitişik bir freed chunk’a taşma → onun “next” pointer’ını üzerine yazmak.
  2. Use-after-free ile freed bir objeye yazma → onun “next” pointer’ını üzerine yazmak.

Sonra, o boyuttaki bir sonraki allocation sırasında:

  • Allocator bozulmuş chunk’ı çıkarır.
  • Saldırgan tarafından sağlanan “next” pointer’ı takip eder.
  • Rastgele belleğe bir pointer döndürür; bu, fake object primitives veya hedefli overwrite’a olanak sağlar.

freelist poisoning’in görsel örneği:

Before corruption:
HEAD ──► [ F1 ] ──► [ F2 ] ──► [ F3 ] ──► NULL

After attacker overwrite of F1->next:
HEAD ──► [ F1 ]
(next) ──► 0xDEAD_BEEF_CAFE_BABE  (attacker-chosen)

Next alloc of this zone → kernel hands out memory at attacker-controlled address.

This freelist design made exploitation highly effective pre-hardening: predictable neighbors from heap sprays, raw pointer freelist links, and no type separation allowed attackers to escalate UAF/overflow bugs into arbitrary kernel memory control.

Heap Grooming / Feng Shui

The goal of heap grooming is to shape the heap layout so that when an attacker triggers an overflow or use-after-free, the target (victim) object sits right next to an attacker-controlled object.
That way, when memory corruption happens, the attacker can reliably overwrite the victim object with controlled data.

Steps:

  1. Spray allocations (fill the holes)
  • Over time, the kernel heap gets fragmented: some zones have holes where old objects were freed.
  • The attacker first makes lots of dummy allocations to fill these gaps, so the heap becomes “packed” and predictable.
  1. Force new pages
  • Once the holes are filled, the next allocations must come from new pages added to the zone.
  • Fresh pages mean objects will be clustered together, not scattered across old fragmented memory.
  • This gives the attacker much better control of neighbors.
  1. Place attacker objects
  • The attacker now sprays again, creating lots of attacker-controlled objects in those new pages.
  • These objects are predictable in size and placement (since they all belong to the same zone).
  1. Free a controlled object (make a gap)
  • The attacker deliberately frees one of their own objects.
  • This creates a “hole” in the heap, which the allocator will later reuse for the next allocation of that size.
  1. Victim object lands in the hole
  • The attacker triggers the kernel to allocate the victim object (the one they want to corrupt).
  • Since the hole is the first available slot in the freelist, the victim is placed exactly where the attacker freed their object.
  1. Overflow / UAF into victim
  • Now the attacker has attacker-controlled objects around the victim.
  • By overflowing from one of their own objects (or reusing a freed one), they can reliably overwrite the victim’s memory fields with chosen values.

Why it works:

  • Zone allocator predictability: allocations of the same size always come from the same zone.
  • Freelist behavior: new allocations reuse the most recently freed chunk first.
  • Heap sprays: attacker fills memory with predictable content and controls layout.
  • End result: attacker controls where the victim object lands and what data sits next to it.

Modern Kernel Heap (iOS 15+/A12+ SoCs)

Apple hardened the allocator and made heap grooming much harder:

1. From Classic kalloc to kalloc_type

  • Before: a single kalloc.<size> zone existed for each size class (16, 32, 64, … 1280, etc.). Any object of that size was placed there → attacker objects could sit next to privileged kernel objects.
  • Now:
  • Kernel objects are allocated from typed zones (kalloc_type).
  • Each type of object (e.g., ipc_port_t, task_t, OSString, OSData) has its own dedicated zone, even if they’re the same size.
  • The mapping between object type ↔ zone is generated from the kalloc_type system at compile time.

An attacker can no longer guarantee that controlled data (OSData) ends up adjacent to sensitive kernel objects (task_t) of the same size.

2. Slabs and Per-CPU Caches

  • The heap is divided into slabs (pages of memory carved into fixed-size chunks for that zone).
  • Each zone has a per-CPU cache to reduce contention.
  • Allocation path:
  1. Try per-CPU cache.
  2. If empty, pull from the global freelist.
  3. If freelist is empty, allocate a new slab (one or more pages).
  • Benefit: This decentralization makes heap sprays less deterministic, since allocations may be satisfied from different CPUs’ caches.

3. Randomization inside zones

  • Within a zone, freed elements are not handed back in simple FIFO/LIFO order.
  • Modern XNU uses encoded freelist pointers (safe-linking like Linux, introduced ~iOS 14).
  • Each freelist pointer is XOR-encoded with a per-zone secret cookie.
  • This prevents attackers from forging a fake freelist pointer if they gain a write primitive.
  • Some allocations are randomized in their placement within a slab, so spraying doesn’t guarantee adjacency.

4. Guarded Allocations

  • Certain critical kernel objects (e.g., credentials, task structures) are allocated in guarded zones.
  • These zones insert guard pages (unmapped memory) between slabs or use redzones around objects.
  • Any overflow into the guard page triggers a fault → immediate panic instead of silent corruption.

5. Page Protection Layer (PPL) and SPTM

  • Even if you control a freed object, you can’t modify all of kernel memory:
  • PPL (Page Protection Layer) enforces that certain regions (e.g., code signing data, entitlements) are read-only even to the kernel itself.
  • On A15/M2+ devices, this role is replaced/enhanced by SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor).
  • These hardware-enforced layers mean attackers can’t escalate from a single heap corruption to arbitrary patching of critical security structures.
  • (Added / Enhanced): also, PAC (Pointer Authentication Codes) is used in the kernel to protect pointers (especially function pointers, vtables) so that forging or corrupting them becomes harder.
  • (Added / Enhanced): zones may enforce zone_require / zone enforcement, i.e. that an object freed can only be returned through its correct typed zone; invalid cross-zone frees may panic or be rejected. (Apple alludes to this in their memory safety posts)

6. Large Allocations

  • Not all allocations go through kalloc_type.
  • Very large requests (above ~16 KB) bypass typed zones and are served directly from kernel VM (kmem) via page allocations.
  • These are less predictable, but also less exploitable, since they don’t share slabs with other objects.

7. Allocation Patterns Attackers Target

Even with these protections, attackers still look for:

  • Reference count objects: if you can tamper with retain/release counters, you may cause use-after-free.
  • Objects with function pointers (vtables): corrupting one still yields control flow.
  • Shared memory objects (IOSurface, Mach ports): these are still attack targets because they bridge user ↔ kernel.

But — unlike before — you can’t just spray OSData and expect it to neighbor a task_t. You need type-specific bugs or info leaks to succeed.

Example: Allocation Flow in Modern Heap

Suppose userspace calls into IOKit to allocate an OSData object:

  1. Type lookupOSData maps to kalloc_type_osdata zone (size 64 bytes).
  2. Check per-CPU cache for free elements.
  • If found → return one.
  • If empty → go to global freelist.
  • If freelist empty → allocate a new slab (page of 4KB → 64 chunks of 64 bytes).
  1. Return chunk to caller.

Freelist pointer protection:

  • Each freed chunk stores the address of the next free chunk, but encoded with a secret key.
  • Overwriting that field with attacker data won’t work unless you know the key.

Comparison Table

FeatureOld Heap (Pre-iOS 15)Modern Heap (iOS 15+ / A12+)
Allocation granularityFixed size buckets (kalloc.16, kalloc.32, etc.)Size + type-based buckets (kalloc_type)
Placement predictabilityHigh (same-size objects side by side)Low (same-type grouping + randomness)
Freelist managementRaw pointers in freed chunks (easy to corrupt)Encoded pointers (safe-linking style)
Adjacent object controlEasy via sprays/frees (feng shui predictable)Hard — typed zones separate attacker objects
Kernel data/code protectionsFew hardware protectionsPPL / SPTM protect page tables & code pages, and PAC protects pointers
Allocation reuse validationNone (freelist pointers raw)zone_require / zone enforcement
Exploit reliabilityHigh with heap spraysMuch lower, requires logic bugs or info leaks
Large allocations handlingAll small allocations managed equallyLarge ones bypass zones → handled via VM

Modern Userland Heap (iOS, macOS — type-aware / xzone malloc)

In recent Apple OS versions (especially iOS 17+), Apple introduced a more secure userland allocator, xzone malloc (XZM). This is the user-space analog to the kernel’s kalloc_type, applying type awareness, metadata isolation, and memory tagging safeguards.

Goals & Design Principles

  • Type segregation / type awareness: group allocations by type or usage (pointer vs data) to prevent type confusion and cross-type reuse.
  • Metadata isolation: separate heap metadata (e.g. free lists, size/state bits) from object payloads so that out-of-bounds writes are less likely to corrupt metadata.
  • Guard pages / redzones: insert unmapped pages or padding around allocations to catch overflows.
  • Memory tagging (EMTE / MIE): work in conjunction with hardware tagging to detect use-after-free, out-of-bounds, and invalid accesses.
  • Scalable performance: maintain low overhead, avoid excessive fragmentation, and support many allocations per second with low latency.

Architecture & Components

Below are the main elements in the xzone allocator:

Segment Groups & Zones

  • Segment groups partition the address space by usage categories: e.g. data, pointer_xzones, data_large, pointer_large.
  • Each segment group contains segments (VM ranges) that host allocations for that category.
  • Associated with each segment is a metadata slab (separate VM area) that stores metadata (e.g. free/used bits, size classes) for that segment. This out-of-line (OOL) metadata ensures that metadata is not intermingled with object payloads, mitigating corruption from overflows.
  • Segments are carved into chunks (slices) which in turn are subdivided into blocks (allocation units). A chunk is tied to a specific size class and segment group (i.e. all blocks in a chunk share the same size & category).
  • For small / medium allocations, it will use fixed-size chunks; for large/huges, it may map separately.

Chunks & Blocks

  • A chunk is a region (often several pages) dedicated to allocations of one size class within a group.
  • Inside a chunk, blocks are slots available for allocations. Freed blocks are tracked via the metadata slab — e.g. via bitmaps or free lists stored out-of-line.
  • Between chunks (or within), guard slices / guard pages may be inserted (e.g. unmapped slices) to catch out-of-bounds writes.

Type / Type ID

  • Every allocation site (or call to malloc, calloc, etc.) is associated with a type identifier (a malloc_type_id_t) which encodes what kind of object is being allocated. That type ID is passed to the allocator, which uses it to select which zone / segment to serve the allocation.
  • Because of this, even if two allocations have the same size, they may go into entirely different zones if their types differ.
  • In early iOS 17 versions, not all APIs (e.g. CFAllocator) were fully type-aware; Apple addressed some of those weaknesses in iOS 18.

Allocation & Freeing Workflow

Here is a high-level flow of how allocation and deallocation operate in xzone:

  1. malloc / calloc / realloc / typed alloc is invoked with a size and type ID.
  2. The allocator uses the type ID to pick the correct segment group / zone.
  3. Within that zone/segment, it seeks a chunk that has free blocks of the requested size.
  • It may consult local caches / per-thread pools or free block lists from metadata.
  • If no free block is available, it may allocate a new chunk in that zone.
  1. The metadata slab is updated (free bit cleared, bookkeeping).
  2. If memory tagging (EMTE) is in play, the returned block gets a tag assigned, and metadata is updated to reflect its “live” state.
  3. When free() is called:
  • The block is marked as freed in metadata (via OOL slab).
  • The block may be placed into a free list or pooled for reuse.
  • Optionally, block contents may be cleared or poisoned to reduce data leaks or use-after-free exploitation.
  • The hardware tag associated with the block may be invalidated or re-tagged.
  • If an entire chunk becomes free (all blocks freed), the allocator may reclaim that chunk (unmap it or return to OS) under memory pressure.

Security Features & Hardening

These are the defenses built into modern userland xzone:

FeaturePurposeNotes
Metadata decouplingPrevent overflow from corrupting metadataMetadata lives in separate VM region (metadata slab)
Guard pages / unmapped slicesCatch out-of-bounds writesHelps detect buffer overflows rather than silently corrupting adjacent blocks
Type-based segregationPrevent cross-type reuse & type confusionEven same-size allocations from different types go to different zones
Memory Tagging (EMTE / MIE)Detect invalid access, stale references, OOB, UAFxzone works in concert with hardware EMTE in synchronous mode (“Memory Integrity Enforcement”)
Delayed reuse / poisoning / zapReduce chance of use-after-free exploitationFreed blocks may be poisoned, zeroed, or quarantined before reuse
Chunk reclamation / dynamic unmappingReduce memory waste and fragmentationEntire chunks may be unmapped when unused
Randomization / placement variationPrevent deterministic adjacencyBlocks in a chunk and chunk selection may have randomized aspects
Segregation of “data-only” allocationsSeparate allocations that don’t store pointersReduces attacker control over metadata or control fields

Interaction with Memory Integrity Enforcement (MIE / EMTE)

  • Apple’s MIE (Memory Integrity Enforcement) is the hardware + OS framework that brings Enhanced Memory Tagging Extension (EMTE) into always-on, synchronous mode across major attack surfaces.
  • xzone allocator is a fundamental foundation of MIE in user space: allocations done via xzone get tags, and accesses are checked by hardware.
  • In MIE, the allocator, tag assignment, metadata management, and tag confidentiality enforcement are integrated to ensure that memory errors (e.g. stale reads, OOB, UAF) are caught immediately, not exploited later.

If you like, I can also generate a cheat-sheet or diagram of xzone internals for your book. Do you want me to do that next?
:contentReference[oai:20]{index=20}

(Old) Physical Use-After-Free via IOSurface

ios Physical UAF - IOSurface


Ghidra Install BinDiff

Download BinDiff DMG from https://www.zynamics.com/bindiff/manual and install it.

Open Ghidra with ghidraRun and go to File –> Install Extensions, press the add button and select the path /Applications/BinDiff/Extra/Ghidra/BinExport and click OK and isntall it even if there is a version mismatch.

Using BinDiff with Kernel versions

  1. Go to the page https://ipsw.me/ and download the iOS versions you want to diff. These will be .ipsw files.
  2. Decompress until you get the bin format of the kernelcache of both .ipsw files. You have information on how to do this on:

macOS Kernel Extensions & Kernelcache

  1. Open Ghidra with ghidraRun, create a new project and load the kernelcaches.
  2. Open each kernelcache so they are automatically analyzed by Ghidra.
  3. Then, on the project Window of Ghidra, right click each kernelcache, select Export, select format Binary BinExport (v2) for BinDiff and export them.
  4. Open BinDiff, create a new workspace and add a new diff indicating as primary file the kernelcache that contains the vulnerability and as secondary file the patched kernelcache.

Finding the right XNU version

If you want to check for vulnerabilities in a specific version of iOS, you can check which XNU release version the iOS version uses at [https://www.theiphonewiki.com/wiki/kernel]https://www.theiphonewiki.com/wiki/kernel).

For example, the versions 15.1 RC, 15.1 and 15.1.1 use the version Darwin Kernel Version 21.1.0: Wed Oct 13 19:14:48 PDT 2021; root:xnu-8019.43.1~1/RELEASE_ARM64_T8006.

iMessage/Media Parser Zero-Click Chains

Imessage Media Parser Zero Click Coreaudio Pac Bypass

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin