iOS Exploiting

Reading time: 65 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

iOS Exploit Mitigations

1. Code Signing / Runtime Signature Verification

Introduced early (iPhone OS → iOS) यह बुनियादी सुरक्षा में से एक है: all executable code (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) को cryptographically sign किया जाना चाहिए एक certificate chain द्वारा जो Apple के trust में rooted हो। runtime पर, किसी binary को memory में load करने से पहले (या कुछ सीमाओं के पार jumps करने से पहले), सिस्टम उसकी signature की जाँच करता है। अगर कोड में संशोधन हुआ है (bit-flipped, patched) या unsigned है, तो load असफल होता है।

  • Thwarts: exploit chains के “classic payload drop + execute” चरण को; arbitrary code injection; मौजूदा binary को malicious logic डालने के लिए modify करने को।
  • Mechanism detail:
  • Mach-O loader (और dynamic linker) code pages, segments, entitlements, team IDs, और यह कि signature file की contents को cover करता है या नहीं, ये सब चेक करते हैं।
  • JIT caches या dynamically generated code जैसी memory regions के लिए, Apple enforce करता है कि pages को sign किया गया हो या special APIs (e.g. mprotect with code-sign checks) के ज़रिये validate किया गया हो।
  • signature में entitlements और identifiers शामिल होते हैं; OS यह enforce करता है कि कुछ APIs या privileged capabilities के लिए specific entitlements चाहिए जो forge नहीं किये जा सकते।
Example मान लीजिए किसी exploit ने किसी process में code execution हासिल कर लिया और heap में shellcode लिखकर उस पर jump करना चाहता है। iOS पर, उस page को executable flag के साथ-साथ code-signature constraints भी satisfy करना होगा। क्योंकि shellcode Apple के certificate से sign नहीं है, तो jump fail हो जाएगा या सिस्टम उस memory region को executable बनाने से मना कर देगा।

2. CoreTrust

Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust वह subsystem है जो binaries (system और user दोनों) की runtime signature validation करता है Apple’s root certificate के खिलाफ, बजाए कि cached userland trust stores पर भरोसा करने के।

  • Thwarts: binaries की post-install tampering, jailbreaking techniques जो system libraries या user apps को swap या patch करके ट्रिक करने की कोशिश करते हैं; trusted binaries को malicious counterparts से replace करने की चालें।
  • Mechanism detail:
  • स्थानीय trust database या certificate cache पर भरोसा करने के बजाय, CoreTrust सीधे Apple’s root की ओर संदर्भित करता है या secure chain में intermediate certificates verify करता है।
  • यह सुनिश्चित करता है कि existing binaries में filesystem में किये गए modifications (उदा. बदलाव) detect होकर reject हो जाएँ।
  • यह entitlements, team IDs, code signing flags, और अन्य metadata को load time पर binary से जोड़ता है।
Example एक jailbreak कोशिश कर सकता है `SpringBoard` या `libsystem` को patched version से replace करने की ताकि persistence मिल सके। लेकिन जब OS का loader या CoreTrust चेक करता है, तो उसे signature mismatch (या modified entitlements) दिखता है और वह execute करने से इनकार कर देता है।

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

Introduced in many OSes earlier; iOS had NX-bit / w^x for a long time DEP enforce करता है कि writable (data के लिए) pages non-executable हों, और executable pages non-writable हों। आप सीधे heap या stack में shellcode नहीं लिखकर उसे execute कर सकते।

  • Thwarts: direct shellcode execution; classic buffer-overflow → injected shellcode पर jump।
  • Mechanism detail:
  • MMU / memory protection flags (page tables के ज़रिये) विभाजन लागू करते हैं।
  • किसी writable page को executable बनाने का कोई भी प्रयास system check trigger करता है (और या तो forbid होता है या code-sign approval चाहिए).
  • कई मामलों में, pages को executable बनाने के लिए OS APIs का उपयोग करना पड़ता है जो अतिरिक्त constraints या checks लगाते हैं।
Example एक overflow heap पर shellcode लिखता है। attacker कोशिश करता है `mprotect(heap_addr, size, PROT_EXEC)` चलाकर उसे executable बनाने की। लेकिन सिस्टम इनकार कर देता है या validate करता है कि नई page को code-sign constraints पास करने होंगे (जो shellcode नहीं कर सकता)।

4. Address Space Layout Randomization (ASLR)

Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR key memory regions के base addresses को randomize करता है: libraries, heap, stack, इत्यादि, प्रत्येक process launch पर। gadgets के addresses runs के बीच बदलते रहते हैं।

  • Thwarts: ROP/JOP के लिए gadget addresses hardcode करना; static exploit chains; known offsets पर blind jumping।
  • Mechanism detail:
  • हर loaded library / dynamic module को एक randomized offset पर rebase किया जाता है।
  • Stack और heap base pointers randomize किये जाते हैं (कुछ entropy limits के अंदर)।
  • कभी-कभी अन्य regions (उदा. mmap allocations) भी randomize होते हैं।
  • information-leak mitigations के साथ मिलकर, यह attacker को मजबूर करता है कि पहले किसी address या pointer का leak करके runtime पर base addresses पता करे।
Example एक ROP chain एक gadget की अपेक्षा करता है `0x….lib + offset` पर। लेकिन चूँकि `lib` हर run पर अलग relocate होता है, hardcoded chain fail हो जाती है। एक exploit को module का base address पता करने के लिए पहले किसी तरह का leak करना होगा ताकि gadget addresses compute किए जा सकें।

5. Kernel Address Space Layout Randomization (KASLR)

Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) user ASLR के समान, KASLR boot time पर kernel text और अन्य kernel structures के base को randomize करता है।

  • Thwarts: kernel-level exploits जो kernel code या data के fixed स्थान पर निर्भर करते हैं; static kernel exploits।
  • Mechanism detail:
  • हर boot पर kernel का base address randomized होता है (एक range के अंदर)।
  • Kernel data structures (जैसे task_structs, vm_map, आदि) भी relocate या offset किए जा सकते हैं।
  • Attackers को पहले kernel pointers leak करना होगा या information disclosure vulnerabilities का उपयोग करके offsets compute करने होंगे, उसके बाद ही kernel structures या code hijack कर पाएँगे।
Example एक local vulnerability kernel function pointer (उदा. किसी `vtable` में) को corrupt करने का लक्ष्य रखती है जो `KERN_BASE + offset` पर है। लेकिन चूँकि `KERN_BASE` अज्ञात है, attacker को पहले उसे leak करना होगा (उदा. किसी read primitive के माध्यम से) ताकि सही address compute कर सके।

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 pages की integrity को लगातार मॉनिटर करता है (hash या checksum के माध्यम से)। अगर यह tampering (patches, inline hooks, code modifications) detect करता है जो allowed windows के बाहर हैं, तो यह kernel panic या reboot trigger करता है।

  • Thwarts: persistent kernel patching (kernel instructions modify करना), inline hooks, static function overwrites।
  • Mechanism detail:
  • एक hardware या firmware module kernel text region को मॉनिटर करता है।
  • यह periodically या on-demand pages को re-hash करता है और expected values से तुलना करता है।
  • अगर mismatches benign update windows के बाहर होते हैं, तो device panic होता है (persistent malicious patch से बचने के लिए)।
  • Attackers को या तो detection windows से बचना होगा या legitimate patch paths का उपयोग करना होगा।
Example एक exploit kernel function prologue (उदा. `memcmp`) को patch करने की कोशिश करता है ताकि calls intercept कर सके। लेकिन KPP देख लेता है कि code page का hash expected value से मेल नहीं खाता और kernel panic trigger कर देता है, जिससे device crash हो जाता है और patch स्थायी रूप से लागू नहीं हो पाती।

7. Kernel Text Read‐Only Region (KTRR)

Introduced in modern SoCs (post ~A12 / newer hardware) KTRR एक hardware-enforced mechanism है: boot के आरंभ में kernel text lock कर देने पर वह EL1 (kernel) से read-only हो जाता है, जिससे code pages पर आगे कोई write संभव नहीं रहता।

  • Thwarts: किसी भी kernel code को boot के बाद modify करने से (उदा. patching, in-place code injection) EL1 privilege level पर।
  • Mechanism detail:
  • boot के दौरान (secure/bootloader stage में), memory controller (या कोई secure hardware unit) physical pages जिनमें kernel text होता है उन्हें read-only mark कर देता है।
  • भले ही कोई exploit full kernel privileges हासिल कर ले, वह उन pages को लिख नहीं सकता।
  • उन्हें modify करने के लिए attacker को पहले boot chain compromise करनी होगी, या KTRR को ही subvert करना होगा।
Example एक privilege-escalation exploit EL1 में जा कर किसी kernel function में trampoline लिखने की कोशिश करता है (उदा. `syscall` handler में)। लेकिन चूँकि pages KTRR द्वारा read-only लॉक किए गए हैं, write fail होता है (या fault trigger होता है), इसलिए patches लागू नहीं होते।

8. Pointer Authentication Codes (PAC)

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

  • PAC एक hardware feature है जो ARMv8.3-A में पेश किया गया था ताकि pointer values (return addresses, function pointers, certain data pointers) के tampering का पता चले — यह pointers के unused उच्च bits में एक छोटा cryptographic signature (“MAC”) embed करके करता है।
  • signature (“PAC”) pointer value और एक modifier (context value, उदा. stack pointer या कोई distinguishing data) के ऊपर compute किया जाता है। इस तरह एक ही pointer value अलग-अलग contexts में अलग PAC देगा।
  • उपयोग के समय, pointer को dereference या branch करने से पहले एक authenticate instruction PAC की जाँच करता है। अगर valid है, PAC strip कर दिया जाता है और शुद्ध pointer मिलता है; अगर invalid है, pointer “poisoned” हो जाता है (या fault उठती है)।
  • PAC बनाने/validate करने के लिए उपयोग होने वाले keys privileged registers (EL1, kernel) में रहते हैं और user mode से सीधे readable नहीं होते।
  • चूँकि बहुत सी प्रणालियों में pointer के सभी 64 bits उपयोग नहीं होते (उदा. 48-bit address space), upper bits spare होते हैं और PAC को बिना प्रभाव डाले वहाँ रखा जा सकता है।

Architectural Basis & Key Types

  • ARMv8.3 में five 128-bit keys introduce किये गए हैं (प्रत्येक दो 64-bit system registers के माध्यम से implement) pointer authentication के लिए।

  • APIAKey — instruction pointers के लिए (domain “I”, key A)

  • APIBKey — दूसरा instruction pointer key (domain “I”, key B)

  • APDAKey — data pointers के लिए (domain “D”, key A)

  • APDBKey — data pointers के लिए (domain “D”, key B)

  • APGAKey — “generic” key, non-pointer data या अन्य generic उपयोग के लिए

  • ये keys privileged system registers में store होते हैं (केवल EL1/EL2 आदि पर accessible), user mode से accessible नहीं।

  • PAC एक cryptographic function (ARM QARMA को सुझाता है) के माध्यम से compute होता है जिसमें शामिल हैं:

  1. Pointer value (canonical portion)
  2. एक modifier (context value, जैसे salt)
  3. Secret key
  4. कुछ internal tweak logic अगर resulting PAC pointer के upper bits में जो stored है उससे match कर जाए, तो authentication सफल माना जाता है।

Instruction Families

नaming convention: PAC / AUT / XPAC, फिर domain letters।

  • PACxx instructions एक pointer को sign करते हैं और PAC insert करते हैं
  • AUTxx instructions authenticate + strip करते हैं (validate करके PAC remove)
  • XPACxx instructions validate न करके strip करते हैं

Domains / suffixes:

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

There are specialized / alias forms:

  • PACIASP shorthand है PACIA X30, SP के लिए (link register को SP को modifier के रूप में sign करना)
  • AUTIASP है AUTIA X30, SP (link register को SP से authenticate करना)
  • Combined forms जैसे RETAA, RETAB (authenticate-and-return) या BLRAA (authenticate & branch) ARM extensions / compiler support में मौजूद हैं।
  • साथ ही zero-modifier variants भी हैं: PACIZA / PACIZB जहाँ modifier implicitly zero होता है, आदि।

Modifiers

modifier का मुख्य उद्देश्य PAC को किसी विशिष्ट context से bind करना है ताकि उसी address को अलग contexts में sign करने पर अलग PAC मिलें। यह pointer reuse across frames या objects को रोकता है — जैसे hash में salt जोड़ना।

इसलिए:

  • modifier एक context value (अन्य register) है जिसे PAC computation में mix किया जाता है। सामान्य विकल्प: stack pointer (SP), frame pointer, या कोई object ID।
  • SP को modifier के रूप में उपयोग करना return address signing के लिए आम है: PAC specific stack frame से जुड़ जाता है। अगर आप LR को दूसरे frame में reuse करने की कोशिश करें, modifier बदल जाएगा, इसलिए PAC validation fail होगी।
  • एक ही pointer value जो अलग modifiers के तहत sign होता है, अलग PAC देगा।
  • modifier को secret होना जरूरी नहीं है, पर ideally यह attacker-controlled न हो।
  • जिन instructions के लिए कोई meaningful modifier नहीं है, वहाँ कुछ forms zero या implicitly constant modifier का उपयोग करते हैं।

Apple / iOS / XNU Customizations & Observations

  • Apple की PAC implementation में per-boot diversifiers शामिल होते हैं ताकि keys या tweaks हर boot पर बदलें, जिससे boot-to-boot reuse रोका जा सके।
  • वे cross-domain mitigations भी शामिल करते हैं ताकि user mode में sign किये गए PAC आसानी से kernel mode में reuse न हो सकें।
  • Apple M1 / Apple Silicon पर reverse engineering से पता चला कि वहाँ nine modifier types और key control के लिए Apple-specific system registers हैं।
  • Apple PAC का उपयोग कई kernel subsystems में होता है: return address signing, pointer integrity in kernel data, signed thread contexts, आदि।
  • Google Project Zero ने दिखाया कि powerful memory read/write primitive होने पर kernel PACs (A keys) को forge करना संभव था (A12-era devices पर), लेकिन Apple ने उन रास्तों के कई patches निकाले।
  • Apple के सिस्टम में कुछ keys global across kernel होते हैं, जबकि user processes को per-process key randomness मिल सकती है।

PAC Bypasses

  1. Kernel-mode PAC: theoretical vs real bypasses
  • क्योंकि kernel PAC keys और logic tightly controlled हैं (privileged registers, diversifiers, domain isolation), arbitrary signed kernel pointers को forge करना बहुत कठिन है।
  • Azad का 2020 "iOS Kernel PAC, One Year Later" रिपोर्ट करता है कि iOS 12-13 में उन्होंने कुछ partial bypasses पाए (signing gadgets, reuse of signed states, unprotected indirect branches) पर कोई full generic bypass नहीं मिला। bazad.github.io
  • Apple की "Dark Magic" customizations exploitable surfaces को और भी सीमित करती हैं (domain switching, per-key enabling bits)। i.blackhat.com
  • Apple silicon (M1/M2) पर एक जाना-पहचाना kernel PAC bypass CVE-2023-32424 है जिसकी रिपोर्ट Zecao Cai et al. ने की थी। i.blackhat.com
  • पर ये bypasses अक्सर बहुत specific gadgets या implementation bugs पर निर्भर करते हैं; वे सामान्य-उद्देश्य bypass नहीं होते।

इसलिए kernel PAC को highly robust माना जाता है, हालांकि परिपूर्ण नहीं।

  1. User-mode / runtime PAC bypass techniques

ये अधिक आम हैं, और PAC के लागू होने या runtime frameworks में उसके उपयोग की imperfections का फायदा उठाते हैं। नीचे classes दी गई हैं, उदाहरणों के साथ।

2.1 Shared Cache / A key issues

  • dyld shared cache एक बड़ा pre-linked blob है system frameworks और libraries का। क्योंकि यह इतनी widely shared है, shared cache के अंदर function pointers "pre-signed" होते हैं और कई processes द्वारा उपयोग किये जाते हैं। Attackers इन पहले से-signed pointers को "PAC oracles" के रूप में target करते हैं।

  • कुछ bypass तकनीकें shared cache में मौजूद A-key signed pointers को extract या reuse करके उन्हें gadgets में reuse करने की कोशिश करती हैं।

  • "No Clicks Required" talk में shared cache पर एक oracle बनाकर relative addresses infer करने और signed pointers combine करके PAC bypass करने का वर्णन है। saelo.github.io

  • साथ ही, userspace में shared libraries से imports of function pointers पर PAC पर्याप्त सुरक्षा नहीं देने पाये गए, जिससे attacker को function pointers मिल जाते थे बिना उनके signature बदलने की आवश्यकता के। (Project Zero bug entry) bugs.chromium.org

2.2 dlsym(3) / dynamic symbol resolution

  • एक ज्ञात bypass यह है कि dlsym() को कॉल करके एक already signed function pointer (A-key से sign किया गया, diversifier zero के साथ) प्राप्त किया जा सकता है और फिर उसे उपयोग किया जा सकता है। क्योंकि dlsym वैध रूप से signed pointer वापस करता है, इसका उपयोग करने से PAC forge करने की जरूरत घट जाती है।

  • Epsilon का ब्लॉग इस पर बताता है कि कुछ bypasses इसे exploit करते हैं: dlsym("someSym") एक signed pointer देता है और indirect calls के लिए उपयोगी हो सकता है। blog.epsilon-sec.com

  • Synacktiv का "iOS 18.4 --- dlsym considered harmful" बताता है कि iOS 18.4 में कुछ symbols जो dlsym से resolve होते थे, pointers गलत तरीके से sign हुए लौटाते थे (या buggy diversifiers के साथ), जिससे unintended PAC bypass संभव हुआ। Synacktiv

  • dyld में लॉजिक यह है कि जब result->isCode, तो वे returned pointer को __builtin_ptrauth_sign_unauthenticated(..., key_asia, 0) से sign करते हैं, यानी context zero। blog.epsilon-sec.com

इसलिए, dlsym user-mode PAC bypasses में एक सामान्य vector है।

2.3 Other DYLD / runtime relocations

  • DYLD loader और dynamic relocation logic जटिल है और कभी-कभी relocations करने के लिए pages को temporarily read/write के रूप में map करता है, फिर उन्हें read-only पर स्विच कर देता है। Attackers इन windows का फायदा उठाते हैं। Synacktiv की talk "Operation Triangulation" में dynamic relocations के माध्यम से timing-based PAC bypass का वर्णन है। Synacktiv

  • DYLD pages अब SPRR / VM_FLAGS_TPRO के साथ protected हैं (dyld के लिए कुछ protection flags)। पर पुराने संस्करणों में guards कमजोर थे। Synacktiv

  • WebKit exploit chains में, DYLD loader अक्सर PAC bypass के लक्ष्यों में से एक रहा है। स्लाइड्स में कहा गया है कि कई PAC bypasses ने DYLD loader को target किया है (relocation, interposer hooks के द्वारा)। Synacktiv

2.4 NSPredicate / NSExpression / ObjC / SLOP

  • userland exploit chains में, Objective-C runtime methods जैसे NSPredicate, NSExpression या NSInvocation का उपयोग control calls को smuggle करने के लिए किया जाता है बिना स्पष्ट pointer forging के।

  • पुराने iOS पर (PAC से पहले), एक exploit ने fake NSInvocation objects का उपयोग करके arbitrary selectors को controlled memory पर कॉल किया। PAC के साथ इसमें बदलाव आवश्यक हुए। पर SLOP (SeLector Oriented Programming) तकनीक PAC के तहत भी विस्तारित की गई है। Project Zero

  • मूल SLOP तकनीक fake invocations बनाकर ObjC calls की chaining की अनुमति देती थी; bypass इस पर निर्भर करता था कि ISA या selector pointers कभी-कभी पूरी तरह PAC-protected नहीं होते थे। Project Zero

  • उन वातावरणों में जहाँ pointer authentication आंशिक रूप से लागू होता है, methods / selectors / target pointers हमेशा PAC protection में नहीं होते, जिससे bypass के लिए जगह मिलती है।

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>Example</summary>
A buffer overflow स्टैक पर एक return address को ओवरराइट कर देता है। हमलावर target gadget address लिखता है लेकिन सही PAC की गणना नहीं कर पाता। जब फ़ंक्शन लौटता है, तो CPU की `AUTIA` instruction fault करती है क्योंकि PAC मेल नहीं खाता। चेन फेल हो जाती है।
Project Zero की A12 (iPhone XS) पर analysis ने दिखाया कि Apple का PAC कैसे उपयोग होता है और PACs को कैसे forge किया जा सकता है यदि एक attacker के पास memory read/write primitive हो।
</details>


### 9. **Branch Target Identification (BTI)**
**Introduced with ARMv8.5 (later hardware)**
BTI एक hardware feature है जो **indirect branch targets** को चेक करता है: जब `blr` या indirect calls/jumps execute होते हैं, तो target का पहला instruction एक **BTI landing pad** (`BTI j` या `BTI c`) से शुरू होना चाहिए। landing pad न होने पर gadget addresses में jump करने से exception ट्रिगर होता है।

LLVM की implementation तीन प्रकार के BTI instructions और उनके branch types से mapping का जिक्र करती है।

| BTI Variant | What it permits (which branch types) | Typical placement / use case |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | Targets of *call*-style indirect branches (e.g. `BLR`, or `BR` using X16/X17) | ऐसे functions के entry पर रखें जिन्हें indirectly call किया जा सकता है |
| **BTI J** | Targets of *jump*-style branches (e.g. `BR` used for tail calls) | उन blocks की शुरुआत में रखें जिन्हें jump tables या tail-calls से पहुंचा जा सकता है |
| **BTI JC** | Acts as both C and J | दोनों call और jump branches द्वारा target किया जा सकता है |

- branch target enforcement के साथ compiled code में, compilers हर valid indirect-branch target (function beginnings या jump से पहुँचने योग्य blocks) पर BTI instruction (C, J, या JC) insert करते हैं ताकि indirect branches केवल उन्हीं जगहों पर सफल हों।
- **Direct branches / calls** (यानी fixed-address `B`, `BL`) BTI द्वारा **नियंत्रित नहीं** होते। माना जाता है कि code pages trusted हैं और attacker उन्हें बदल नहीं सकता (इसलिए direct branches सुरक्षित माने जाते हैं)।
- साथ ही, **RET / return** instructions आमतौर पर BTI द्वारा सीमित नहीं होते क्योंकि return addresses को PAC या return signing mechanisms के जरिए सुरक्षित किया जाता है।

#### Mechanism and enforcement

- जब CPU किसी page पर marked “guarded / BTI-enabled” में एक **indirect branch (BLR / BR)** decode करता है, तो यह चेक करता है कि target address का पहला instruction एक valid BTI (C, J, या JC जैसा-permitted) है या नहीं। यदि नहीं, तो **Branch Target Exception** होता है।
- BTI instruction encoding को ऐसे design किया गया है कि वह पुराने ARM versions में NOPs के लिए reserved opcodes का reuse करे। इसलिए BTI-enabled binaries backward-compatible रहते हैं: BTI-सपोर्ट नहीं वाले hardware पर वे instructions NOPs की तरह काम करते हैं।
- BTI add करने वाले compiler passes उन्हें केवल आवश्यक जगहों पर insert करते हैं: वे functions जिन्हें indirectly call किया जा सकता है, या basic blocks जिन्हें jumps target करते हैं।
- कुछ patches और LLVM code दिखाते हैं कि BTI सभी basic blocks के लिए insert नहीं किया जाता — केवल उन blocks के लिए जो potential branch targets हैं (जैसे switch / jump tables से)।

#### BTI + PAC synergy

PAC pointer value (source) की रक्षा करता है — यह सुनिश्चित करता है कि indirect calls / returns की chain में tampering नहीं हुआ है।

BTI यह सुनिश्चित करता है कि एक valid pointer केवल सही तरीके से marked entry points को ही target कर सके।

साथ मिलकर, एक attacker को दोनों चाहिए होंगे: एक valid pointer सही PAC के साथ और target पर BTI होना चाहिए। इससे exploit gadgets बनाने की कठिनाई बढ़ जाती है।

#### Example


<details>
<summary>Example</summary>
एक exploit `0xABCDEF` पर मौजूद gadget में pivot करने की कोशिश करता है जो `BTI c` से शुरू नहीं होता। CPU, `blr x0` execute करने पर target को चेक करता है और instruction alignment में valid landing pad न होने पर fault कर देता है। इस तरह कई gadgets तब तक उपयोगी नहीं रहते जब तक कि उनके आगे BTI prefix मौजूद न हो।
</details>


### 10. **Privileged Access Never (PAN) & Privileged Execute Never (PXN)**
**Introduced in more recent ARMv8 extensions / iOS support (for hardened kernel)**

#### PAN (Privileged Access Never)

- **PAN** एक feature है जो **ARMv8.1-A** में पेश किया गया था और यह सुनिश्चित करता है कि **privileged code** (EL1 या EL2) **user-accessible (EL0)** के रूप में marked memory को **read या write** न कर सके, जब तक कि PAN स्पष्ट रूप से disabled न किया गया हो।
- विचार यह है कि अगर kernel को trick या compromise भी किया जाए, तो वह user-space pointers को बिना पहले PAN clear किए arbitrary तरीके से dereference नहीं कर सकता, जिससे **`ret2usr`** शैली के exploits या user-controlled buffers के दुरुपयोग का खतरा कम होता है।
- जब PAN enabled होता है (PSTATE.PAN = 1), तो कोई भी privileged load/store instruction जो ऐसे virtual address पर access करता है जो “accessible at EL0” है, वह एक **permission fault** ट्रिगर करता है।
- जब kernel को legitimate तरीके से user-space memory को access करना होता है (जैसे user buffers में data copy करना), तो kernel को अस्थायी रूप से **PAN disable** करना पड़ता है (या “unprivileged load/store” instructions का उपयोग करना पड़ता है) ताकि वह access कर सके।
- Linux on ARM64 में PAN support लगभग 2015 के आसपास जोड़ी गई थी: kernel patches ने feature detection जोड़ी और `get_user` / `put_user` आदि को उन variants से बदल दिया जो user memory accesses के चारों ओर PAN clear करते हैं।

**Key nuance / limitation / bug**
- जैसा कि Siguza और अन्य लोगों ने नोट किया, ARM की design में एक specification bug (या ambiguous व्यवहार) है जिससे **execute-only user mappings** (`--x`) पर PAN लागू न होने की संभावना है। यानी अगर कोई user page executable है पर read permission नहीं है, तो kernel का पढ़ने का प्रयास PAN को bypass कर सकता है क्योंकि architecture “accessible at EL0” को readable permission की आवश्यकता मानता है, केवल executable होना पर्याप्त नहीं मानता। यह कुछ ARMv8+ implementations में PAN bypass की ओर ले जा सकता है।
- इस वजह से, यदि iOS / XNU execute-only user pages की अनुमति देता है (जैसे कुछ JIT या code-cache सेटअप्स करते हैं), तो kernel संभवतः PAN enabled होने पर भी उनसे पढ़ सकता है। यह कुछ ARMv8+ सिस्टम्स में ज्ञात एक सूक्ष्म exploitable area है।

#### PXN (Privileged eXecute Never)

- **PXN** एक page table flag है (page table entries, leaf या block entries में) जो दर्शाता है कि वह page **privileged mode में executables के लिए non-executable** है (यानी जब EL1 execute कर रहा हो)।
- PXN kernel (या किसी भी privileged code) को user-space pages से jump करने या वहां से instructions execute करने से रोकता है भले ही control वहां divert हो जाए। मूल रूप से यह kernel-level control-flow redirection into user memory को रोकता है।
- PAN के साथ मिलकर, यह सुनिश्चित करता है कि:
1. Kernel by default user-space data को read/write न कर सके (PAN)
2. Kernel user-space code को execute न कर सके (PXN)
- ARMv8 page table format में, leaf entries के attribute bits में `PXN` bit होता है (और unprivileged execute-never के लिए `UXN` भी होता है)।

इसलिए भले ही kernel के पास एक corrupted function pointer हो जो user memory की ओर इशारा करता हो, और वह वहां branch करने की कोशिश करे, PXN bit fault करवा देगा।

#### Memory-permission model & how PAN and PXN map to page table bits

PAN / PXN कैसे काम करते हैं समझने के लिए ARM की translation और permission model को देखना होगा (सरल किया हुआ):

- हर page या block entry में attribute fields होते हैं जिनमें **AP[2:1]** शामिल है जो access permissions (read/write, privileged vs unprivileged) दर्शाता है और execute-never restrictions के लिए **UXN / PXN** bits होते हैं।
- जब PSTATE.PAN 1 (enabled) होता है, तो hardware संशोधित semantics लागू करता है: privileged accesses उन pages पर जो “accessible by EL0” के रूप में marked हैं उन्हें disallow करता है (fault)।
- ऊपर बताये गए bug के कारण, केवल executable (read permission नहीं) के रूप में marked pages कुछ implementations में “accessible by EL0” नहीं माने जा सकते—जिससे PAN bypass संभव होता है।
- जब किसी page का PXN bit set होता है, तो भले ही instruction fetch higher privilege level से हो, execution prohibited होता है।

#### Kernel usage of PAN / PXN in a hardened OS (e.g. iOS / XNU)

एक hardened kernel design (जैसे Apple शायद उपयोग करता है) में:

- Kernel डिफ़ॉल्ट रूप से PAN enable रखता है (ताकि privileged code constrained रहे)।
- उन रास्तों में जहाँ kernel legitimately user buffers पढ़/लिख सकता है (जैसे syscall buffer copy, I/O, read/write user pointer), kernel अस्थायी रूप से **PAN disable** करता है या user memory access override करने वाली special instructions उपयोग करता है।
- user data access समाप्त करने के बाद, उसे PAN फिर से enable कर देना चाहिए।
- PXN page tables के माध्यम से लागू होता है: user pages में PXN = 1 होता है (ताकि kernel वहां से execute न कर सके), kernel pages में PXN नहीं होता (ताकि kernel code execute कर सके)।
- Kernel को सुनिश्चित करना चाहिए कि कोई code path execution flow को user memory regions में न ले जाए (क्योंकि वह PXN को bypass कर सकता है) — इसलिए exploit chains जो “user-controlled shellcode में jump” पर निर्भर हैं, वे blocked रहते हैं।

चूँकि execute-only pages के जरिए PAN bypass का मुद्दा मौजूद है, वास्तविक सिस्टम में Apple संभवतः execute-only user pages को disable कर दे या specification weakness को patch कर दे।

#### Attack surfaces, bypasses, and mitigations

- **PAN bypass via execute-only pages**: जैसा ऊपर चर्चा हुई, spec में एक गैप है: execute-only (read permission न रखने वाले) user pages कुछ implementations में “accessible at EL0” नहीं माने जा सकते, इसलिए PAN kernel के उन पेजों से पढ़ने को block नहीं करेगा। इससे attacker के लिए execute-only sections के जरिए डेटा भेजने का एक असामान्य रास्ता बन सकता है।
- **Temporal window exploit**: यदि kernel आवश्यकता से अधिक समय तक PAN disable कर देता है, तो एक race या malicious path उस विंडो का फायदा उठा सकता है और unintended user memory access कर सकता है।
- **Forgotten re-enable**: यदि code paths PAN को पुनः enable करना भूल जाते हैं, तो बाद के kernel operations गलती से user memory को access कर सकते हैं।
- **Misconfiguration of PXN**: यदि page tables user pages पर PXN सेट नहीं करते या user code pages को गलत तरीके से map करते हैं, तो kernel को user-space code execute करने के लिए trick किया जा सकता है।
- **Speculation / side-channels**: speculative bypasses के समान, microarchitectural side-effects हो सकते हैं जो PAN / PXN checks का transient उल्लंघन करें (हालाँकि ऐसे attacks CPU design पर अत्यधिक निर्भर करते हैं)।
- **Complex interactions**: advanced features (जैसे JIT, shared memory, just-in-time code regions) में kernel को user-mapped regions में कुछ memory accesses या execution की अनुमति देने के लिएละเอียด नियंत्रण चाहिए; PAN/PXN constraints के तहत इन्हें सुरक्षित रूप से डिजाइन करना कठिन होता है।

#### Example

<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>
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">  </span></div>

// 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

यदि kernel ने उस user page पर **PXN** सेट नहीं किया होता, तो branch सफल हो सकती थी — जो असुरक्षित होगा।

यदि kernel user memory access के बाद PAN को पुनः सक्षम करना भूल जाता है, तो एक विंडो खुल जाती है जहाँ आगे की kernel लॉजिक गलती से arbitrary user memory को read/write कर सकती है।

यदि user pointer किसी execute-only page (ऐसा user page जिसमें केवल execute परमिशन है, read/write नहीं) में है, तो PAN spec बग के तहत, `ldr W2, [X1]` PAN सक्षम होने पर भी fault **नहीं** कर सकता, जो implementation पर निर्भर करते हुए bypass exploit सक्षम कर सकता है।

</details>

<details>
<summary>Example</summary>
एक kernel vulnerability user-provided function pointer लेकर उसे kernel context में कॉल करने की कोशिश करती है (यानी `call user_buffer`)। PAN/PXN के अंतर्गत, वह ऑपरेशन disallowed है या fault करता है।
</details>

---

### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI का मतलब है कि 64-bit pointer का top byte (सबसे-महत्वपूर्ण बाइट) address translation द्वारा ignore किया जाता है। इससे OS या hardware pointer के top byte में **tag bits** embed कर सकते हैं बिना असली address को प्रभावित किए।

- TBI का पूरा नाम **Top Byte Ignore** है (कभी-कभी *Address Tagging* कहा जाता है)। यह एक hardware फीचर है (कई ARMv8+ implementations में उपलब्ध) जो कि 64-bit pointer के top 8 bits (bits 63:56) को address translation / load/store / instruction fetch करते समय **ignore** कर देता है।
- परिणामस्वरूप, CPU एक pointer `0xTTxxxx_xxxx_xxxx` (जहाँ `TT` = top byte) को address translation के प्रयोजनों के लिए `0x00xxxx_xxxx_xxxx` की तरह मानता है, top byte को mask करके। top byte को software द्वारा **metadata / tag bits** रखने के लिए इस्तेमाल किया जा सकता है।
- इससे software को प्रत्येक pointer में एक byte का tag इन-बैंड मुफ्त में एम्बेड करने की जगह मिलती है, बिना यह बदले कि वह किस memory location को रेफर करता है।
- architecture सुनिश्चित करता है कि loads, stores, और instruction fetch pointer के top byte masked (यानी tag हटाकर) ही memory access करते हैं।

इस प्रकार TBI logical pointer (pointer + tag) को physical address से अलग कर देता है जो memory operations के लिए उपयोग होता है।

#### Why TBI: Use cases and motivation

- **Pointer tagging / metadata**: आप extra metadata (जैसे object type, version, bounds, integrity tags) top byte में स्टोर कर सकते हैं। जब बाद में pointer का उपयोग करेंगे, hardware लेवल पर tag ignore हो जाएगा, इसलिए memory access के लिए manually strip करने की आवश्यकता नहीं होगी।
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI वही बेस hardware मैकेनिज्म है जिस पर MTE बनता है। ARMv8.5 में, **Memory Tagging Extension** pointer के bits 59:56 को एक **logical tag** के रूप में उपयोग करता है और इसे memory में स्टोर किए गए **allocation tag** के साथ चेक करता है।
- **Enhanced security & integrity**: TBI को pointer authentication (PAC) या runtime checks के साथ मिलाकर आप न सिर्फ pointer value बल्कि tag की सत्यता भी सुनिश्चित कर सकते हैं। एक attacker द्वारा pointer overwrite करने पर यदि tag सही नहीं है तो tag mismatch होगा।
- **Compatibility**: क्योंकि TBI optional है और tag bits hardware द्वारा ignore किए जाते हैं, मौजूदा untagged code सामान्य रूप से काम करना जारी रखता है। tag bits विरासत कोड के लिए "don’t care" बिट्स बन जाते हैं।

#### Example
<details>
<summary>Example</summary>
एक function pointer के top byte में एक tag था (मान लें `0xAA`)। एक exploit pointer के low bits को overwrite कर देती है लेकिन tag छोड़ देती है, इसलिए जब kernel verify या sanitize करता है, तो pointer fail या reject हो जाता है।
</details>

---

### 12. **Page Protection Layer (PPL)**
**Introduced in late iOS / modern hardware (iOS ~17 / Apple silicon / high-end models)** (कुछ रिपोर्ट्स PPL को macOS / Apple silicon पर दिखाती हैं, लेकिन Apple iOS पर समकक्ष protections ला रहा है)

- PPL एक **intra-kernel protection boundary** के रूप में डिज़ाइन किया गया है: भले ही kernel (EL1) compromised हो और उसके पास read/write क्षमताएँ हों, **वहCertain sensitive pages को स्वतंत्र रूप से modify नहीं कर पाना चाहिए** (खासकर page tables, code-signing metadata, kernel code pages, entitlements, trust caches, आदि)।
- यह प्रभावी रूप से एक “kernel के अंदर kernel” बनाता है — एक छोटा trusted component (PPL) जिसे केवल protected pages modify करने की **उच्च विशेषाधिकार** प्राप्त होती है। अन्य kernel कोड को protected बदलाव करने के लिए PPL routines में कॉल करना होता है।
- इससे kernel exploits के लिए attack surface कम हो जाता है: भले ही kernel में full arbitrary R/W/execute हो, exploit code को protected structures modify करने के लिए PPL डोमेन में भी प्रवेश करना होगा (या PPL को bypass करना होगा)।
- नए Apple silicon (A15+ / M2+) पर Apple कई मामलों में page-table protection के लिए **SPTM (Secure Page Table Monitor)** की ओर जा रहा है, जो PPL की जगह ले सकता है।

यहाँ PPL कैसे काम करता है, यह सार्वजनिक विश्लेषण के आधार पर अनुमानित रूप में दिया गया है:

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

- Apple hardware एक मैकेनिज्म का उपयोग करती है जिसे **APRR (Access Permission ReRouting)** कहा जाता है, जो page table entries (PTEs) को पूर्ण permission bits के बजाय छोटे indices रखने की अनुमति देता है। वे indices APRR registers के माध्यम से वास्तविक permissions से map होते हैं। यह domain-प्रति dynamic remapping की अनुमति देता है।
- PPL APRR का लाभ उठाता है ताकि kernel context के भीतर privileges को अलग किया जाए: केवल PPL domain को indices और effective permissions के बीच mapping अपडेट करने की अनुमति होती है। यानी जब non-PPL kernel code कोई PTE लिखता है या permission bits बदलने की कोशिश करता है, तो APRR logic उसे disallow करता है (या read-only mapping लागू करता है)।
- PPL कोड स्वयं एक restricted region में चलता है (उदा. `__PPLTEXT`) जो सामान्यतः entry gates तक non-executable या non-writable रहता है जब तक कि अस्थायी रूप से अनुमति न दी जाए। kernel protected operations करने के लिए PPL entry points (“PPL routines”) को कॉल करता है।

#### Gate / Entry & Exit

- जब kernel को किसी protected page को modify करना होता है (उदा. kernel code page की permissions बदलना, या page tables modify करना), तो वह एक **PPL wrapper** routine में कॉल करता है, जो validation करती है और फिर PPL डोमेन में transition करती है। उस डोमेन के बाहर protected pages मूलतः read-only या non-modifiable होते हैं।
- PPL entry के दौरान, APRR mappings समायोजित किए जाते हैं ताकि PPL region की memory pages PPL के भीतर **executable & writable** सेट हो जाएँ। exit पर उन्हें फिर से read-only / non-writable कर दिया जाता है। इससे केवल अच्छे तरीके से audit किए गए PPL routines ही protected pages लिख सकें।
- PPL के बाहर, kernel code द्वारा उन protected pages पर write करने के प्रयत्न fault करेंगे (permission denied), क्योंकि उस code domain के लिए APRR mapping लिखने की अनुमति नहीं देती।

#### Protected page categories

PPL सामान्यतः जिन पेजों को protect करता है उनमें शामिल हैं:

- Page table structures (translation table entries, mapping metadata)
- Kernel code pages, विशेषकर वे जिनमें critical logic होता है
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tables, signature enforcement tables
- अन्य high-value kernel structures जहाँ patch करने से signature checks या credentials manipulation bypass हो सकता है

विचार यह है कि भले ही kernel memory पूरी तरह नियंत्रित हो, attacker इन पेजों को सीधे patch या rewrite नहीं कर सकता, जब तक कि वे PPL routines को compromise न कर लें या PPL bypass न कर लें।

#### Known Bypasses & Vulnerabilities

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

- Project Zero द्वारा एक public writeup में stale TLB entries से जुड़ा bypass वर्णित किया गया है।
- विचार इस प्रकार है:

1. दो physical pages A और B allocate करें, उन्हें PPL pages के रूप में mark करें (तो वे protected हों)।
2. दो virtual addresses P और Q map करें जिनकी L3 translation table pages A और B से आती हैं।
3. एक thread चलाएँ जो लगातार Q को एक्सेस करे, जिससे उसका TLB entry alive रहे।
4. `pmap_remove_options()` को कॉल करें ताकि P से mappings remove हों; एक बग के कारण, कोड गलती से P और Q दोनों के TTEs remove कर देता है, लेकिन केवल P के लिए TLB entry invalidate करता है, जिससे Q का stale entry जीवित रह जाता है।
5. B (page Q का table) को पुनः उपयोग करके arbitrary memory map करें (उदा. PPL-protected pages)। क्योंकि stale TLB entry अभी भी Q के पुराने mapping को map करता है, वह mapping उस context के लिए मान्य बनी रहती है।
6. इसके माध्यम से attacker PPL-protected pages का writable mapping बिना PPL interface के जगह पर रख सकता है।

- इस exploit के लिए physical mapping और TLB व्यवहार पर सूक्ष्म नियंत्रण की आवश्यकता थी। यह दर्शाता है कि TLB / mapping correctness पर आधारित सुरक्षा सीमा को TLB invalidations और mapping consistency के बारे में बेहद सावधान रहना चाहिए।
- Project Zero ने टिप्पणी की कि इस तरह के bypasses सूक्ष्म और दुर्लभ होते हैं, पर जटिल प्रणालियों में संभव हैं। फिर भी, वे PPL को एक मजबूत mitigation मानते हैं।

2. **Other potential hazards & constraints**

- यदि एक kernel exploit सीधे PPL routines में प्रवेश कर सकता है (PPL wrappers को कॉल कर के), तो वह प्रतिबंधों को bypass कर सकता है। इसलिए argument validation महत्वपूर्ण है।
- PPL कोड में ही बग्स (उदा. arithmetic overflow, boundary checks) अंदरूनी रूप से PPL के भीतर out-of-bounds modifications की अनुमति दे सकते हैं। Project Zero ने देखा कि `pmap_remove_options_internal()` में ऐसा ही एक बग उनके bypass में इस्तेमाल हुआ था।
- PPL boundary हार्डवेयर एन्फोर्समेंट (APRR, memory controller) से अपरिवर्तनीय रूप से जुड़ी होती है, इसलिए इसकी मजबूती हार्डवेयर implementation जितनी ही मजबूत है।

#### Example
<details>
<summary>Code Example</summary>
Here’s a simplified pseudocode / logic showing how a kernel might call into PPL to modify protected pages:
</details>
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">c</span></div>

```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
Example Kernel कई सामान्य ऑपरेशन कर सकता है, लेकिन केवल `ppl_call_*` रूटीन के माध्यम से ही यह protected mappings बदल सकता है या कोड में पैच कर सकता है।
Example A kernel exploit entitlement table को overwrite करने या kernel signature blob को modify करके code-sign enforcement को disable करने की कोशिश कर सकता है। क्योंकि वह पेज PPL-protected है, वह write तब तक blocked रहता है जब तक कि PPL interface के माध्यम से न जाएँ। इसलिए भले ही kernel code execution हो, आप code-sign constraints को bypass नहीं कर सकते या credential data को मनमाने ढंग से modify नहीं कर सकते। iOS 17+ पर कुछ डिवाइस SPTM का उपयोग करके PPL-managed पृष्ठों को और अलग कर देते हैं।

PPL → SPTM / प्रतिस्थापन / भविष्य

  • Apple के आधुनिक SoCs (A15 or later, M2 or later) पर, Apple SPTM (Secure Page Table Monitor) का समर्थन करता है, जो पेज टेबल सुरक्षा के लिए PPL को प्रतिस्थापित करता है।
  • Apple दस्तावेज़ में बताता है: “Page Protection Layer (PPL) और Secure Page Table Monitor (SPTM) हस्ताक्षरित और भरोसेमंद कोड के निष्पादन को लागू करते हैं … PPL पेज टेबल अनुमति ओवरराइड्स का प्रबंधन करता है … Secure Page Table Monitor समर्थित प्लेटफार्मों पर PPL को प्रतिस्थापित करता है.”
  • SPTM आर्किटेक्चर संभवतः पॉलिसी लागू करने को kernel नियंत्रण के बाहर एक उच्च-प्रिविलेज्ड मॉनिटर में स्थानांतरित करता है, जिससे trust boundary और घटती है।

MTE | EMTE | MIE

यहाँ Apple के MIE सेटअप के तहत EMTE कैसे काम करता है, इसका उच्च-स्तरीय विवरण है:

  1. Tag assignment
  • जब मेमोरी allocate की जाती है (उदा. kernel या user space में secure allocators के माध्यम से), उस ब्लॉक को एक secret tag सौंपा जाता है।
  • उपयोगकर्ता या kernel को वापसी में दिया गया pointer उसके high bits में वह tag शामिल करता है (TBI / top byte ignore mechanisms का उपयोग करके)।
  1. Tag checking on access
  • जब भी किसी pointer का उपयोग करके load या store executed होता है, hardware यह जांचता है कि pointer का tag memory block के tag (allocation tag) से मेल खाता है या नहीं। यदि mismatch होता है, तो तुरंत fault होता है (क्योंकि synchronous)।
  • चूंकि यह synchronous है, इसलिए कोई “delayed detection” विंडो नहीं होती।
  1. Retagging on free / reuse
  • जब मेमोरी free की जाती है, allocator उस ब्लॉक का tag बदल देता है (ताकि पुराने pointers जिनके पास पुराने tags हैं वे अब मेल न खाएँ)।
  • एक use-after-free pointer इसलिए stale tag रखेगा और एक्सेस पर mismatch होगा।
  1. Neighbor-tag differentiation to catch overflows
  • आसन्न allocations को अलग-अलग tags दिए जाते हैं। अगर एक buffer overflow पड़ोसी की मेमोरी में फैलता है, तो tag mismatch fault पैदा कर देगा।
  • यह boundary पार करने वाले छोटे overflows पकड़ने में विशेष रूप से प्रभावशाली है।
  1. Tag confidentiality enforcement
  • Apple को tag मानों के leak को रोकना होगा (क्योंकि अगर attacker tag जान लेता है, तो वह सही tags वाले pointers बना सकता है)।
  • उन्होंने tag बिट्स के side-channel leakage से बचने के लिए protections (microarchitectural / speculative controls) शामिल किए हैं।
  1. Kernel and user-space integration
  • Apple EMTE का उपयोग केवल user-space में ही नहीं बल्कि kernel / OS-critical components में भी करता है (kernel को memory corruption से बचाने के लिए)।
  • hardware/OS यह सुनिश्चित करते हैं कि tag नियम तब भी लागू हों जब kernel user space की ओर से execute कर रहा हो।
Example ``` 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>

#### सीमाएँ और चुनौतियाँ

- **Intrablock overflows**: यदि overflow एक ही allocation के भीतर रहता है (boundary पार नहीं करता) और टैग वही रहता है, तो tag mismatch इसे पकड़ नहीं पाता।
- **Tag width limitation**: tag के लिए केवल कुछ बिट्स उपलब्ध होते हैं (उदा. 4 bits, या छोटा domain)—सीमित namespace।
- **Side-channel leaks**: यदि tag बिट्स leak हो सकते हैं (cache / speculative execution के माध्यम से), attacker वैध tags जान सकता है और bypass कर सकता है। Apple की tag confidentiality enforcement इसे mitigate करने का प्रयत्न है।
- **Performance overhead**: हर load/store पर tag checks लागत जोड़ते हैं; Apple को hardware को optimize करना होगा ताकि overhead कम रहे।
- **Compatibility & fallback**: पुराने hardware या उन हिस्सों पर जो EMTE को support नहीं करते, fallback मौजूद होना जरूरी है। Apple का दावा है कि MIE केवल उन्हीं डिवाइसों पर enabled है जिनमें support है।
- **Complex allocator logic**: allocator को tags, retagging, boundary alignment manage करना होगा और mis-tag collisions से बचना होगा। allocator logic में बग vulnerabilities पैदा कर सकते हैं।
- **Mixed memory / hybrid areas**: कुछ memory legacy कारणों से untagged रह सकती है, जिससे interoperability जटिल हो जाती है।
- **Speculative / transient attacks**: कई microarchitectural protections की तरह, speculative execution या micro-op fusions checks को transient रूप से bypass कर सकती हैं या tag बिट्स को leak कर सकती हैं।
- **Limited to supported regions**: Apple संभवतः EMTE को selective, high-risk क्षेत्रों (kernel, security-critical subsystems) में ही enforce करे, न कि सार्वभौमिक रूप से।


---

## Key enhancements / differences compared to standard MTE

यहाँ वे improvements और परिवर्तन हैं जिन पर Apple जोर देता है:

| Feature | Original MTE | EMTE (Apple’s enhanced) / MIE |
|---|---|---|
| **Check mode** | Supports synchronous and asynchronous modes. In async, tag mismatches are reported later (delayed)| Apple insists on **synchronous mode** by default—tag mismatches are caught immediately, no delay/race windows allowed.|
| **Coverage of non-tagged memory** | Accesses to non-tagged memory (e.g. globals) may bypass checks in some implementations | EMTE requires that accesses from a tagged region to non-tagged memory also validate tag knowledge, making it harder to bypass by mixing allocations.|
| **Tag confidentiality / secrecy** | Tags might be observable or leaked via side channels | Apple adds **Tag Confidentiality Enforcement**, which attempts to prevent leakage of tag values (via speculative side-channels etc.).|
| **Allocator integration & retagging** | MTE leaves much of allocator logic to software | Apple’s secure typed allocators (kalloc_type, xzone malloc, etc.) integrate with EMTE: when memory is allocated or freed, tags are managed at fine granularity.|
| **Always-on by default** | In many platforms, MTE is optional or off by default | Apple enables EMTE / MIE by default on supported hardware (e.g. iPhone 17 / A19) for kernel and many user processes.|

क्योंकि Apple hardware और software दोनों नियंत्रित करता है, यह EMTE को कड़ाई से enforce कर सकता है, performance pitfalls से बच सकता है, और side-channel holes बंद कर सकता है।

---

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

नीचे एक उच्च-स्तरीय विवरण है कि Apple के MIE सेटअप में EMTE कैसे काम करता है:

1. **Tag assignment**
- जब memory allocate की जाती है (उदा. kernel या user space में secure allocators के माध्यम से), उस block को एक **secret tag** दिया जाता है।
- user या kernel को लौटाया गया pointer उस tag को इसके high bits में शामिल करता है (TBI / top byte ignore mechanisms का उपयोग करके)।

2. **Tag checking on access**
- जब भी कोई load या store किसी pointer के साथ executed होता है, hardware जांचता है कि pointer का tag memory block के tag (allocation tag) से मेल खाता है या नहीं। अगर mismatch होता है, तो तुरंत fault होता है (क्योंकि synchronous)।
- चूंकि यह synchronous है, इसलिए कोई “delayed detection” window नहीं होता।

3. **Retagging on free / reuse**
- जब memory free होती है, allocator block का tag बदल देता है (ताकि पुराने pointers जिनमें पुराना tag है, match न करें)।
- इसलिए एक use-after-free pointer stale tag रखेगा और access पर mismatch होगा।

4. **Neighbor-tag differentiation to catch overflows**
- आस-पास की allocations को अलग-अलग tags दिए जाते हैं। यदि कोई buffer overflow पड़ोसी की memory में spill करता है, तो tag mismatch fault पैदा कर देगा।
- यह विशेष रूप से छोटे overflows को पकड़ने में प्रभावी है जो boundary cross करते हैं।

5. **Tag confidentiality enforcement**
- Apple को tag values के leak होने से रोकना होगा (क्योंकि अगर attacker tag जान लेता है, तो वह सही tags के साथ pointers बना सकता है)।
- वे tag bits के speculative side-channels आदि के माध्यम से leakage रोकने के लिए protections शामिल करते हैं।

6. **Kernel and user-space integration**
- Apple EMTE का उपयोग केवल user-space में ही नहीं बल्कि kernel / OS-critical components में भी करता है (kernel को memory corruption से बचाने के लिए)।
- hardware/OS यह सुनिश्चित करते हैं कि tag नियम तब भी लागू हों जब kernel user space की ओर से execute कर रहा हो।

क्योंकि EMTE MIE में बिल्ट है, Apple प्रमुख attack surfaces में synchronous mode में EMTE का उपयोग करता है, इसे opt-in या debugging mode के रूप में नहीं रखता।

---

## Exception handling in XNU

जब एक **exception** होती है (उदा., `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, आदि), तो XNU kernel की **Mach layer** इसे UNIX-style **signal** (जैसे `SIGSEGV`, `SIGBUS`, `SIGILL`, ...) बनने से पहले intercept करने के लिए जिम्मेदार होती है।

यह प्रक्रिया user space तक पहुँचने या BSD signal में convert होने से पहले कई layers के exception propagation और handling में शामिल होती है।

### Exception Flow (High-Level)

1.  **CPU triggers a synchronous exception** (उदा., invalid pointer dereference, PAC failure, illegal instruction, आदि)।

2.  **Low-level trap handler** चलता है (`trap.c`, `exception.c` in XNU source)।

3.  trap handler **`exception_triage()`** को कॉल करता है, जो Mach exception handling का core है।

4.  `exception_triage()` तय करता है कि exception को कैसे route किया जाए:

-   पहले **thread's exception port** को।

-   फिर **task's exception port** को।

-   फिर **host's exception port** को (अक्सर `launchd` या `ReportCrash`)।

यदि इनमे से कोई port exception को handle नहीं करता, तो kernel:

-   **इसे BSD signal में convert कर देता है** (user-space processes के लिए), या

-   **panic** करता है (kernel-space exceptions के लिए)।

### Core Function: `exception_triage()`

फंक्शन `exception_triage()` Mach exceptions को संभावित handlers की श्रृंखला में route करता है जब तक कि कोई handler इसे handle न कर ले या यह अंततः fatal न बन जाए। यह `osfmk/kern/exception.c` में defined है।
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">c</span></div>

```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);

सामान्य कॉल फ़्लो:

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

यदि सभी विफल होते हैं → bsd_exception() द्वारा संभाला जाता है → एक सिग्नल जैसे SIGSEGV में अनुवादित किया जाता है।

Exception Ports

प्रत्येक Mach object (thread, task, host) exception ports रजिस्टर कर सकता है, जहाँ exception messages भेजे जाते हैं।

वे API द्वारा परिभाषित होते हैं:

task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()

प्रत्येक एक्सेप्शन पोर्ट के पास:

  • एक मास्क (यह किस एक्सेप्शन को प्राप्त करना चाहता है)
  • एक पोर्ट नाम (Mach पोर्ट जो संदेश प्राप्त करेगा)
  • एक बिहेवियर (कर्नेल संदेश कैसे भेजता है)
  • एक फ्लेवर (कौन सा thread state शामिल किया जाएगा)

डिबगर्स और एक्सेप्शन हैंडलिंग

एक डिबगर (उदा., LLDB) लक्षित task या thread पर एक एक्सेप्शन पोर्ट सेट करता है, आमतौर पर task_set_exception_ports() का उपयोग करके।

जब कोई एक्सेप्शन होता है:

  • Mach संदेश डिबगर प्रक्रिया को भेजा जाता है।
  • डिबगर निर्णय ले सकता है कि वह इसे हैंडल करे (resume, registers बदलना, instruction skip करना) या नहीं हैन्डल करे।
  • अगर डिबगर इसे हैंडल नहीं करता, तो एक्सेप्शन अगले स्तर पर फैलता है (task → host).

EXC_BAD_ACCESS का फ्लो

  1. Thread किसी अमान्य pointer को dereference करता है → CPU Data Abort उठाता है।

  2. Kernel trap handler exception_triage(EXC_BAD_ACCESS, ...) को कॉल करता है।

  3. संदेश भेजा जाता है:

  • Thread पोर्ट → (डिबगर ब्रेकपॉइंट को इंटरसेप्ट कर सकता है)।

  • अगर डिबगर अनदेखा करता है → Task पोर्ट → (प्रोसेस-लेवल हैंडलर)।

  • अगर अनदेखा किया जाता है → Host पोर्ट (आम तौर पर ReportCrash)।

  1. अगर कोई हैंडल नहीं करता → bsd_exception() इसे SIGSEGV में ट्रांसलेट कर देता है।

PAC एक्सेप्शन्स

जब Pointer Authentication (PAC) फेल होता है (signature mismatch), एक विशेष Mach एक्सेप्शन उठाया जाता है:

  • EXC_ARM_PAC (type)
  • Codes में विवरण हो सकते हैं (उदा., key type, pointer type).

अगर बाइनरी में फ्लैग TFRO_PAC_EXC_FATAL set है, तो कर्नेल PAC फेलियर्स को fatal मानता है, और डिबगर इंटरसेप्शन को बायपास कर देता है। यह इसलिए किया गया है ताकि attackers डिबगर का उपयोग करके PAC checks को बायपास न कर सकें और यह platform binaries के लिए सक्षम होता है।

सॉफ़्टवेयर ब्रेकपॉइंट्स

एक सॉफ़्टवेयर ब्रेकपॉइंट (int3 on x86, brk on ARM64) को जानबूझ कर fault उत्पन्न करके इम्प्लीमेंट किया जाता है.
डिबगर इसे exception पोर्ट के माध्यम से पकड़ता है:

  • instruction pointer या memory को संशोधित करता है।
  • मूल instruction को पुनर्स्थापित करता है।
  • execution पुनः आरंभ करता है।

यही मेकैनिज़्म आपको एक PAC एक्सेप्शन "catch" करने की अनुमति देता है --- जब तक TFRO_PAC_EXC_FATAL सेट न हो, उस स्थिति में यह कभी डिबगर तक नहीं पहुँचता।

BSD सिग्नल्स में रूपांतरण

अगर कोई हैंडलर एक्सेप्शन स्वीकार नहीं करता:

  • कर्नेल task_exception_notify() → bsd_exception() को कॉल करता है।

  • यह Mach एक्सेप्शन्स को सिग्नल्स में मैप करता है:

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

XNU स्रोत में प्रमुख फाइलें

  • osfmk/kern/exception.cexception_triage(), exception_deliver_*() का कोर।

  • bsd/kern/kern_sig.c → सिग्नल डिलिवरी लॉजिक।

  • osfmk/arm64/trap.c → लो-लेवल trap handlers।

  • osfmk/mach/exc.h → एक्सेप्शन कोड्स और स्ट्रक्चर्स।

  • osfmk/kern/task.c → Task exception पोर्ट सेटअप।


पुराना Kernel Heap (Pre-iOS 15 / Pre-A12 युग)

कर्नेल एक zone allocator (kalloc) का उपयोग करता था जो फिक्स्ड-साइज़ "ज़ोन्स" में विभाजित था। प्रत्येक ज़ोन केवल एक सिंगल साइज क्लास के allocations स्टोर करता था।

स्क्रीनशॉट से:

Zone NameElement SizeExample Use
default.kalloc.1616 bytesबहुत छोटे kernel structs, pointers.
default.kalloc.3232 bytesछोटे structs, object headers.
default.kalloc.6464 bytesIPC messages, छोटे kernel buffers.
default.kalloc.128128 bytesमध्यम ऑब्जेक्ट जैसे OSObject के हिस्से।
default.kalloc.12801280 bytesबड़े स्ट्रक्चर्स, IOSurface/graphics metadata.

यह इस प्रकार काम करता था:

  • प्रत्येक allocation अनुरोध को निकटतम zone size तक round up किया जाता था। (उदा., 50-बाइट का अनुरोध kalloc.64 ज़ोन में जाएगा)।
  • प्रत्येक ज़ोन में मेमोरी एक freelist में रखी जाती थी — कर्नेल द्वारा फ्री की गई chunks उसी ज़ोन में वापस जाती थीं।
  • अगर आप एक 64-बाइट buffer overflow करते थे, तो आप उसी ज़ोन के अगले ऑब्जेक्ट को overwrite कर देते थे।

यही कारण है कि heap spraying / feng shui इतना प्रभावी था: आप एक ही साइज क्लास के allocations स्प्रे करके ऑब्जेक्ट соседों की भविष्यवाणी कर सकते थे।

The freelist

प्रत्येक kalloc ज़ोन के अंदर, फ्री किए गए ऑब्जेक्ट्स सीधे सिस्टम को वापस नहीं किए जाते थे — वे freelist में जाते थे, उपलब्ध chunks की एक linked list।

  • जब एक chunk फ्री किया जाता था, कर्नेल उस chunk की शुरुआत में एक pointer लिखता था → उसी ज़ोन के अगले फ्री chunk का पता।

  • ज़ोन एक HEAD pointer रखता था जो पहले फ्री chunk की ओर इशारा करता था।

  • Allocation हमेशा मौजूदा HEAD का उपयोग करता था:

  1. HEAD को pop करना (वह मेमोरी caller को वापस की जाती है)।

  2. HEAD = HEAD->next अपडेट करना (जो फ्री किए गए chunk के हेडर में संग्रहीत था)।

  • Freeing chunks को वापस पुश करता था:

  • freed_chunk->next = HEAD

  • HEAD = freed_chunk

तो freelist बस मुक्त मेमोरी के अंदर ही निर्मित एक linked list थी।

सामान्य स्थिति:

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)

Exploiting the freelist

क्योंकि किसी free chunk के पहले 8 बाइट freelist pointer के बराबर होते हैं, एक हमलावर इसे corrupt कर सकता है:

  1. Heap overflow एक adjacent freed chunk में → उसके “next” pointer को overwrite कर देना।

  2. Use-after-free के दौरान freed object में write करके → उसके “next” pointer को overwrite कर देना।

फिर, उस size की अगली allocation पर:

  • Allocator corrupted chunk को pop करता है।

  • attacker-supplied “next” pointer का अनुसरण करता है।

  • Arbitrary memory के लिए pointer return करता है, जिससे fake object primitives या targeted overwrite संभव होते हैं।

Visual example of freelist poisoning:

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 डिजाइन हार्डनिंग से पहले exploitation को अत्यंत प्रभावी बनाती थी: heap sprays से अनुमानित पड़ोसी, raw pointer freelist links, और किसी भी प्रकार का विभाजन न होने के कारण हमलावर UAF/overflow बग्स को arbitrary kernel memory control में escalate कर सकते थे।

Heap Grooming / Feng Shui

Heap grooming का लक्ष्य है कि heap लेआउट को आकार देना ताकि जब हमलावर overflow या use-after-free ट्रिगर करे, तो लक्ष्य (victim) ऑब्जेक्ट सीधे attacker-controlled ऑब्जेक्ट के बगल में बैठा हो।
इस तरह, जब memory corruption होता है, हमलावर विश्वसनीय रूप से victim ऑब्जेक्ट को नियंत्रित डेटा से overwrite कर सकता है।

Steps:

  1. Spray allocations (fill the holes)
  • समय के साथ, kernel heap fragmented हो जाता है: कुछ zones में ऐसे holes रहते हैं जहाँ पुराने objects free हुए थे।
  • हमलावर पहले बहुत सी dummy allocations करके इन गैप्स को भरता है, ताकि heap “packed” और predictable हो जाए।
  1. Force new pages
  • एक बार holes भर दिए जाने पर, अगली allocations को उस zone में नई pages से आना होगा।
  • ताज़ा pages का मतलब है कि objects एक साथ clustered होंगे, पुराने fragmented memory में बिखरे हुए नहीं।
  • इससे हमलावर को पड़ोसियों पर बेहतर नियंत्रण मिलता है।
  1. Place attacker objects
  • हमलावर अब फिर से spray करता है, उन नई pages में बहुत से attacker-controlled objects बनाता है।
  • ये ऑब्जेक्ट आकार और प्लेसमेंट में predictable होते हैं (क्योंकि वे सभी उसी zone से आते हैं)।
  1. Free a controlled object (make a gap)
  • हमलावर जानबूझकर अपनी किसी object को free कर देता है।
  • इससे heap में एक “hole” बनता है, जिसे allocator बाद में उसी size की अगली allocation के लिए reuse करेगा।
  1. Victim object lands in the hole
  • हमलावर kernel को ट्रिगर करता है ताकि victim ऑब्जेक्ट allocate हो।
  • चूँकि hole freelist में पहली उपलब्ध slot है, victim ठीक उसी जगह पर रखा जाता है जहाँ हमलावर ने अपनी object free की थी।
  1. Overflow / UAF into victim
  • अब हमलावर के पास victim के आस-पास attacker-controlled ऑब्जेक्ट होते हैं।
  • अपनी किसी ऑब्जेक्ट से overflow करके (या freed ऑब्जेक्ट का reuse करके), वे विश्वसनीय रूप से victim की memory fields को चुने हुए मानों से overwrite कर सकते हैं।

क्यों यह काम करता है:

  • Zone allocator की predictability: एक ही size की allocations हमेशा उसी zone से आती हैं।
  • Freelist व्यवहार: नई allocations सबसे हाल में freed chunk को पहले reuse करती हैं।
  • Heap sprays: हमलावर स्मृति को predictable content से भरता है और layout को नियंत्रित करता है।
  • अंत में: हमलावर नियंत्रित करता है कि victim ऑब्जेक्ट कहाँ land करे और उसके बगल में कौन सा डेटा हो।

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

Apple ने allocator को मजबूत किया और heap grooming को काफी मुश्किल बना दिया:

1. From Classic kalloc to kalloc_type

  • Before: प्रत्येक size class (16, 32, 64, … 1280, आदि) के लिए एक single kalloc.<size> zone मौजूद था। उस size का कोई भी ऑब्जेक्ट वहीं रखा जाता था → attacker ऑब्जेक्ट privileged kernel objects के बगल में रखे जा सकते थे।
  • Now:
  • Kernel objects अब typed zones (kalloc_type) से allocate होते हैं।
  • प्रत्येक प्रकार के ऑब्जेक्ट (उदा., ipc_port_t, task_t, OSString, OSData) का अपना dedicated zone होता है, भले ही उनका आकार समान हो।
  • object type ↔ zone का mapping compile time पर kalloc_type system से जनरेट होता है।

हमलावर अब यह सुनिश्चित नहीं कर सकता कि controlled डेटा (OSData) sensitive kernel objects (task_t) के साथ उसी size पर adjacent आ जाएगा।

2. Slabs and Per-CPU Caches

  • heap को slabs में विभाजित किया गया है (pages जिन्हें उस zone के fixed-size chunks में काटा गया है)।
  • हर zone में contention कम करने के लिए per-CPU cache होता है।
  • Allocation path:
  1. पहले per-CPU cache चेक करें।
  2. अगर खाली है, तो global freelist से लें।
  3. अगर freelist भी खाली है, तो नया slab allocate करें (एक या अधिक pages)।
  • लाभ: यह decentralized तरीका heap sprays को कम deterministic बनाता है, क्योंकि allocations अलग-अलग CPUs के caches से पूरी हो सकती हैं।

3. Randomization inside zones

  • एक zone के भीतर, freed elements सरल FIFO/LIFO क्रम में वापस नहीं दिए जाते।
  • आधुनिक XNU encoded freelist pointers का उपयोग करता है (Linux जैसी safe-linking, ~iOS 14 में लागू)।
  • प्रत्येक freelist pointer को per-zone secret cookie के साथ XOR-encoded किया जाता है।
  • इससे अगर हमलावर को write primitive मिल भी जाए तो वह नकली freelist pointer बनाने से रोका जाता है।
  • कुछ allocations को slab के भीतर उनकी placement में randomized किया जाता है, इसलिए spraying adjacency की गारंटी नहीं देता।

4. Guarded Allocations

  • कुछ महत्वपूर्ण kernel objects (उदा., credentials, task structures) guarded zones में allocate किए जाते हैं।
  • ये zones slabs के बीच guard pages (unmapped memory) डालते हैं या objects के चारों ओर redzones का उपयोग करते हैं।
  • guard page में किसी भी overflow से fault ट्रिगर होता है → silent corruption की बजाय immediate panic।

5. Page Protection Layer (PPL) and SPTM

  • भले ही आप किसी freed object को नियंत्रित कर लें, आप kernel की पूरी memory को modify नहीं कर सकते:
  • PPL (Page Protection Layer) यह लागू करता है कि कुछ क्षेत्रों (उदा., code signing data, entitlements) kernel के लिए भी read-only हों।
  • A15/M2+ devices पर यह भूमिका SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor) द्वारा बदली/बढ़ाई गई है।
  • ये hardware-enforced layers सुनिश्चित करते हैं कि हमलावर एक single heap corruption से critical security structures को arbitrary patch नहीं कर पाएँ।
  • (Added / Enhanced): kernel में pointers (विशेषकर function pointers, vtables) की सुरक्षा के लिए PAC (Pointer Authentication Codes) का उपयोग किया जाता है ताकि उन्हें forge/ corrupt करना कठिन हो।
  • (Added / Enhanced): zones zone_require / zone enforcement लागू कर सकते हैं, यानी कि freed object केवल अपने सही typed zone के माध्यम से ही वापस आ सकता है; गलत cross-zone frees panic करवा सकते हैं या reject किए जा सकते हैं। (Apple अपनी memory safety पोस्ट्स में इसका जिक्र करती है)

6. Large Allocations

  • सभी allocations kalloc_type से नहीं गुजरते।
  • बहुत बड़े अनुरोध (~16 KB से ऊपर) typed zones को बाईपास करते हैं और सीधे kernel VM (kmem) से page allocations के माध्यम से serve होते हैं।
  • ये कम predictable होते हैं, पर कम exploitable भी होते हैं, क्योंकि वे अन्य objects के साथ slabs शेयर नहीं करते।

7. Allocation Patterns Attackers Target

इन सुरक्षा उपायों के बावजूद, हमलावर अभी भी इन चीज़ों की तलाश करते हैं:

  • Reference count objects: अगर आप retain/release काउंटर्स में छेड़छाड़ कर सकें तो use-after-free पैदा हो सकता है।
  • Objects with function pointers (vtables): एक को corrupt करना अभी भी control flow दे सकता है।
  • Shared memory objects (IOSurface, Mach ports): ये अभी भी निशाने पर हैं क्योंकि वे user ↔ kernel का पुल होते हैं।

पर — पहले की तरह — आप बस OSData spray करके यह उम्मीद नहीं कर सकते कि वह task_t के पास आ जाएगा। सफल होने के लिए आपको type-specific bugs या info leaks की ज़रूरत होती है।

Example: Allocation Flow in Modern Heap

मान लीजिए userspace IOKit में कॉल करके एक OSData ऑब्जेक्ट allocate कराता है:

  1. Type lookupOSData map होता है kalloc_type_osdata zone (size 64 bytes) पर।
  2. Per-CPU cache में free elements चेक करें।
  • अगर मिला → उसे return करें।
  • अगर खाली → global freelist में जाएँ।
  • अगर freelist खाली → नया slab allocate करें (4KB का page → 64 chunks of 64 bytes)।
  1. chunk caller को return करें।

Freelist pointer protection:

  • प्रत्येक freed chunk में अगले free chunk का पता store होता है, पर वह secret key के साथ encoded होता है।
  • attacker data से उस फ़ील्ड को overwrite करने पर तब तक काम नहीं करेगा जब तक आप 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)

हालिया Apple OS वर्शन (खासकर iOS 17+ में), Apple ने userland allocator xzone malloc (XZM) पेश किया। यह kernel के kalloc_type का user-space समकक्ष है, जो type awareness, metadata isolation, और memory tagging safeguards लागू करता है।

Goals & Design Principles

  • Type segregation / type awareness: allocations को type या उपयोग (pointer vs data) के अनुसार group करना ताकि type confusion और cross-type reuse रोका जा सके।
  • Metadata isolation: heap metadata (जैसे free lists, size/state bits) को object payloads से अलग रखना ताकि out-of-bounds writes से metadata corrupt होने की संभावना कम हो।
  • Guard pages / redzones: allocations के चारों ओर unmapped pages या padding डालना ताकि overflows पकड़े जा सकें।
  • Memory tagging (EMTE / MIE): hardware tagging के साथ मिलकर use-after-free, out-of-bounds, और invalid accesses का पता लगाने में मदद करना।
  • Scalable performance: कम overhead बनाए रखना, अधिक fragmentation से बचना, और प्रति सेकंड कई allocations का low-latency समर्थन करना।

Architecture & Components

नीचे xzone allocator के मुख्य तत्व हैं:

Segment Groups & Zones

  • Segment groups address space को usage categories से partition करते हैं: उदा., data, pointer_xzones, data_large, pointer_large
  • प्रत्येक segment group में segments (VM ranges) होते हैं जो उस category के allocations होस्ट करते हैं।
  • प्रत्येक segment के साथ एक metadata slab (separate VM area) जुड़ा होता है जो metadata (उदा., free/used bits, size/classes) रखता है। यह out-of-line (OOL) metadata सुनिश्चित करता है कि metadata object payloads के साथ intermingle न हो, जिससे overflows से corruption कम हो।
  • Segments को chunks (slices) में काटा जाता है जो फिर blocks (allocation units) में subdivide होते हैं। एक chunk एक specific size class और segment group से जुड़ा होता है (यानी उस chunk के सभी blocks एक ही size & category साझा करते हैं)।
  • small/medium allocations के लिए fixed-size chunks उपयोग होते हैं; very large/huge allocations के लिए अलग mapping हो सकती है।

Chunks & Blocks

  • एक chunk एक क्षेत्र है (अक्सर कई pages) जो एक size class के allocations के लिए समर्पित होता है।
  • एक chunk के अंदर blocks allocation के स्लॉट होते हैं। freed blocks को metadata slab के माध्यम से ट्रैक किया जाता है — उदा., bitmaps या out-of-line free lists के जरिये।
  • chunks के बीच (या अंदर) guard slices / guard pages डाले जा सकते हैं (उदा., unmapped slices) ताकि out-of-bounds writes पकड़े जा सकें।

Type / Type ID

  • हर allocation site (या malloc, calloc, आदि को कॉल करने पर) एक type identifier (malloc_type_id_t) से जुड़ा होता है जो बताता है कि किस तरह का ऑब्जेक्ट allocate हो रहा है। यह type ID allocator को दिया जाता है, जो इसे सही zone/segment चुनने के लिए उपयोग करता है।
  • इसलिए, भले ही दो allocations का आकार समान हो, उनके types अलग होने पर वे पूरी तरह अलग zones में जा सकते हैं।
  • iOS 17 के पहले वर्ज़न में, सभी APIs (उदा., CFAllocator) पूरी तरह type-aware नहीं थीं; Apple ने iOS 18 में कुछ कमजोरियों को संबोधित किया।

Allocation & Freeing Workflow

यहाँ xzone में allocation और deallocation का high-level flow है:

  1. malloc / calloc / realloc / typed alloc को size और type ID के साथ बुलाया जाता है।
  2. allocator type ID का उपयोग करके सही segment group / zone चुनता है।
  3. उस zone/segment के भीतर, वह उस size के लिए free blocks वाला chunk खोजता है।
  • यह local caches / per-thread pools या metadata से free block lists देख सकता है।
  • अगर कोई free block उपलब्ध नहीं है, तो वह उस zone में नया chunk allocate कर सकता है।
  1. metadata slab अपडेट होता है (free bit cleared, bookkeeping)।
  2. अगर memory tagging (EMTE) सक्रिय है, तो वापस किया गया block एक tag पा लेता है और metadata इसकी “live” स्थिति दर्शाने के लिए अपडेट होता है।
  3. जब free() कॉल होती है:
  • block metadata में freed के रूप में चिह्नित होता है (OOL slab के माध्यम से)।
  • block को reuse के लिए free list या pool में रखा जा सकता है।
  • वैकल्पिक रूप से, data leaks या use-after-free exploitation को कम करने के लिए block contents को clear या poison किया जा सकता है।
  • block से जुड़ा hardware tag invalidate या re-tag किया जा सकता है।
  • अगर पूरा chunk free हो जाता है (सभी blocks free), allocator memory pressure पर उस chunk को reclaim कर सकता है (unmap करना या OS को वापस करना)।

Security Features & Hardening

ये आधुनिक userland xzone में निर्मित रक्षा हैं:

FeaturePurposeNotes
Metadata decouplingPrevent overflow from corrupting metadataMetadata अलग VM region (metadata slab) में रहता है
Guard pages / unmapped slicesCatch out-of-bounds writesBuffer overflows को silent corruption के बजाय पकड़ने में मदद करता है
Type-based segregationPrevent cross-type reuse & type confusionभले ही size समान हो, अलग types अलग zones में जाते हैं
Memory Tagging (EMTE / MIE)Detect invalid access, stale references, OOB, UAFxzone hardware EMTE के साथ synchronous mode में काम करता है (“Memory Integrity Enforcement”)
Delayed reuse / poisoning / zapReduce chance of use-after-free exploitationFreed blocks को poison, zero, या quarantine किया जा सकता है
Chunk reclamation / dynamic unmappingReduce memory waste and fragmentationअनयूज़्ड chunks को unmapped किया जा सकता है
Randomization / placement variationPrevent deterministic adjacencyChunk और block selection में randomized पहलू हो सकते हैं
Segregation of “data-only” allocationsSeparate allocations that don’t store pointersउन allocations को अलग करना जो pointers नहीं रखते, metadata या control fields पर attacker नियंत्रण कम करता है

Interaction with Memory Integrity Enforcement (MIE / EMTE)

  • Apple का MIE (Memory Integrity Enforcement) hardware + OS फ्रेमवर्क है जो Enhanced Memory Tagging Extension (EMTE) को major attack surfaces पर always-on, synchronous mode में लाता है।
  • xzone allocator user space में MIE का आधार है: xzone के माध्यम से की गई allocations को tags मिलते हैं, और accesses hardware द्वारा चेक किए जाते हैं।
  • MIE में allocator, tag assignment, metadata management, और tag confidentiality enforcement को एकीकृत किया गया है ताकि memory errors (उदा., stale reads, OOB, UAF) तुरंत पकड़े जाएँ और बाद में exploit न हो सकें।

अगर आप चाहें तो मैं आपके बुक के लिए xzone internals का cheat-sheet या diagram भी बना कर दे सकता हूँ। क्या आप चाहेंगे कि मैं अगला ऐसा बनाऊँ? ::contentReference[oai:20]{index=20}


(Old) Physical Use-After-Free via IOSurface

ios Physical UAF - IOSurface


Ghidra Install BinDiff

BinDiff DMG को https://www.zynamics.com/bindiff/manual से डाउनलोड करें और इंस्टॉल करें।

Ghidra को ghidraRun से खोलें और File --> Install Extensions पर जाएँ, add बटन दबाएँ और path /Applications/BinDiff/Extra/Ghidra/BinExport चुनें और OK पर क्लिक कर के install करें भले ही version mismatch हो।

Using BinDiff with Kernel versions

  1. उस पेज पर जाएँ https://ipsw.me/ और वे iOS versions डाउनलोड करें जिन्हें आप diff करना चाहते हैं। ये .ipsw फाइलें होंगी।
  2. decompress करें जब तक कि आपको दोनों .ipsw फाइलों के kernelcache का bin format न मिल जाए। इसको कैसे करना है इसके बारे में जानकारी आपको मिल सकती है:

macOS Kernel Extensions & Kernelcache

  1. Ghidra को ghidraRun से खोलें, एक नया project बनाएं और kernelcaches लोड करें।
  2. प्रत्येक kernelcache खोलें ताकि वे Ghidra द्वारा स्वतः analyze हो जाएँ।
  3. फिर, Ghidra के project Window पर प्रत्येक kernelcache पर right click करें, Export चुनें, format में Binary BinExport (v2) for BinDiff चुनें और export करें।
  4. BinDiff खोलें, एक नया workspace बनाएं और एक नया diff जोड़ें जिसमें primary file वह kernelcache हो जो vulnerability रखता है और secondary file patched kernelcache हो।

Finding the right XNU version

अगर आप किसी specific version के iOS में vulnerabilities चेक करना चाहते हैं, तो आप यह देख सकते हैं कि वह iOS किस XNU release version का उपयोग करता है इस पेज पर: [https://www.theiphonewiki.com/wiki/kernel]https://www.theiphonewiki.com/wiki/kernel).

उदाहरण के लिए, versions 15.1 RC, 15.1 और 15.1.1 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 हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें