TrigonLegacy: The 17-Year-Old iOS Kernel Bug That Still Grants TFP0 in Under 10ms + Video

Listen to this Post

Featured Image

Introduction

In an era where Apple’s security mitigations grow increasingly sophisticated, the discovery of a kernel vulnerability that survived across 17 years of XNU evolution is nothing short of remarkable. The TrigonLegacy exploit, released on February 28, 2026, demonstrates how an ancient integer overflow in the VM layer—present since the earliest days of XNU and assigned CVE-2023-32434—can be weaponized to achieve deterministic tfp0 (task-for-pid-0) on iOS 7 through 9 devices. By combining this legacy bug with modern exploitation techniques and creative bypasses, researchers have crafted an exploit that runs in under 10 milliseconds with a 100% success rate across over 500,000 tests.

Learning Objectives

  • Understand the root cause of CVE-2023-32434 and how an integer overflow in `mach_make_memory_entry_64` enables out-of-bounds memory mapping
  • Learn the step-by-step methodology for achieving arbitrary physical memory read/write primitives on legacy iOS devices
  • Master the techniques for locating kernel base addresses, parsing translation tables, and ultimately building a tfp0 port without relying on unreliable patchfinding
  • Explore the use of pipes as a deterministic kernel read/write primitive and understand how to achieve 100% reliability
  1. The Bug That Refused to Die: Understanding CVE-2023-32434

At the heart of TrigonLegacy lies a deceptively simple integer overflow in the `mach_make_memory_entry_64` function. The vulnerable code, which persisted from `xnu-124` through iOS 16.5, performs a bounds check that fails to account for overflow conditions:

if ((offset + map_size) > parent_entry->size) {
kr = KERN_INVALID_ARGUMENT;
goto make_mem_done;
}

All three variables—offset, map_size, and parent_entry->size—are attacker-controlled. By crafting values that cause the sum to overflow, an attacker can bypass the check entirely. For example:

offset = 0x2000
map_size = 0xfffffffffffff000
parent_entry->size = 0x4000

The sum `0x2000 + 0xfffffffffffff000` overflows to 0x1000, which is less than 0x4000, allowing the creation of a memory entry that maps far beyond its intended bounds.

The Fix: Apple eventually patched this in iOS 16.5.1 by adding an overflow check using os_add_overflow:

if (__improbable(os_add_overflow(offset, map_size, &tmp))) {
kr = KERN_INVALID_ARGUMENT;
goto make_mem_done;
}

Interestingly, the buggy check was gated behind flags like `MAP_MEM_USE_DATA_ADDR` and MAP_MEM_4K_DATA_ADDR—flags that 99.9% of callers never set. This created a classic case of “tunnel vision,” where researchers overlooked the actual reachable codepath for years.

Step-by-Step: Triggering the Overflow

  1. Create an IOSurface backed by `PurpleGfxMem` to obtain physically contiguous memory
  2. For iOS 7, which lacks `IOSurfaceCreate` support for PurpleGfxMem, steal the default framebuffer surface via `create_default_fb_surface`
    3. Create two memory entries: a parent entry backed by the IOSurface, and a child entry with `size = UINT64_MAX – page_size + 1` and `offset = 2 page_size`
    4. Use `mach_vm_map` with the child entry to map arbitrary physical pages

Linux/Windows Command Equivalents: While this is iOS-specific, the concept of integer overflows in memory management is universal. On Linux, similar issues have been found in the `mmap` system call. To test for overflow conditions in your own code:

 Linux: Check for integer overflow in size calculations
gcc -Wall -Wextra -fsanitize=undefined -o test test.c

On Windows, use the `/analyze` flag in MSVC to detect potential overflow issues:

cl /analyze /W4 test.c
  1. Finding Your Bearings: Locating the Kernel Base Without Panicking

With the physical mapping primitive in hand, the next challenge is locating the kernel base address. Simply scanning backwards from the VRAM mapping triggers spinlock panics when hitting process memory or random kernel structures. Scanning forwards eventually hits unmapped memory, also causing a panic.

The Sleep Token Trick: For A8(X) devices and below, the sleep token buffer resides at a fixed physical address every boot. By hardcoding this address (discovered via PongoOS) and scanning forward until finding the `XSOMNNUR` magic value, the exploit can determine its exact mapping base.

For A9 Devices: While A9 uses the reconfig engine and has no use for a sleep token, the memory region still exists in iOS 9 and can be leveraged.

Physical Kernel Slide: On A9, the physical kernel slide is derived from the virtual slide, with only 16 possible values. This makes brute-forcing the kernel header location trivial—a 2000× speedup compared to scanning.

Step-by-Step: Finding the Kernel Base

  1. Boot PongoOS and locate the `stram` entry in the device tree to find the sleep token buffer base
  2. Map forward from the mapping base until the `XSOMNNUR` magic is found
  3. Subtract the mapping address from the hardcoded sleep token address to get the exact physical mapping base
  4. For A7/A8, the kernel header is always located immediately after the last TrustZone region at the start of DRAM
  5. For A9, iterate through the 16 possible physical slides until the kernel header is found

Code Snippet: Parsing the Kernel Header

// Extract kernel base from Mach-O header
uint64_t kernel_base = physical_kernel_base;
struct mach_header_64 header = (struct mach_header_64 )kernel_base;
if (header->magic == MH_MAGIC_64) {
// Parse load commands to find __TEXT segment
// Extract vmaddr for virtual base
}
  1. From Physical to Virtual: Building the kvtophys Primitive

With the kernel base known, the next step is converting virtual addresses to physical addresses—essential for reading and writing kernel structures. The key is locating `TTBR1_EL1` (the root translation table base, also known as cpu_ttep).

The Boot_args Shortcut: Through reverse engineering, researchers discovered that `cpu_ttep` is always located at boot_args->topOfKernelData + 0x10000 + 0x4000. By finding the `boot_args` structure, `cpu_ttep` falls into place.

Finding boot_args: The `boot_args` region sits after the DeviceTree, which follows the last segment of the kernel image. By parsing the kernel Mach-O header and locating `__PRELINK_INFO` or __PRELINK_TEXT, the exploit maps a few pages forward and looks for the `boot_args` magic.

Step-by-Step: Building kvtophys

  1. Parse the kernel Mach-O header to get segment virtual addresses and calculate physical offsets
  2. Locate `__PRELINK_TEXT` and map forward to find the DeviceTree

3. Scan for the `boot_args` magic value

4. Extract `topOfKernelData` from `boot_args`

  1. Calculate `cpu_ttep = topOfKernelData + 0x10000 + 0x4000`
    6. Traverse the translation tables using `cpu_ttep` to convert any virtual address to physical

Verification Commands: On Linux, you can examine the kernel’s page tables via:

 View process page tables
sudo cat /proc/self/pagemap

Dump kernel page table information
sudo cat /proc/kpagecount
sudo cat /proc/kpageflags

On Windows, use WinDbg to inspect translation tables:

!pte <virtual_address>
!vtop <physical_address>
  1. The Quest for TFP0: Building the Kernel Task Port

TFP0—a send right to the kernel task—grants full control over the kernel’s vm_map, enabling arbitrary kernel memory read/write via `mach_vm_` APIs. To build a tfp0 port, three conditions must be met:

– `IP_RECEIVER` must point to `ipc_space_kernel`
– `IP_KOBJECT` must point to `kernel_task`
– `IE_BITS` must have `IE_BITS_SEND` set

Finding kernel_task: The initial approach—patchfinding the `kernproc` symbol—proved problematic because the symbol table is wiped at runtime (unless `keepsyms=1` is set, which it never is on stock devices). The exploit instead uses a unique instruction oracle to find kernproc.

The CVE-2020-3836 Info Leak: By triggering `IOSURFACE_SET_NOTIFY` with a mach port, then calling `IOSurfaceIncrementUseCount` and IOSurfaceDecrementUseCount, the kernel returns a message containing the port’s own kernel address. This allows the exploit to locate its own `proc` struct and traverse the linked list to find `kernproc` (pid 0).

Step-by-Step: Building TFP0

  1. Trigger the CVE-2020-3836 info leak to get a port address
  2. Traverse the `proc` linked list from the current process until `pid == 0` is found

3. Read `task_bsd_info` from `kernproc` to get `kernel_task`

  1. Patch an existing port’s `IP_RECEIVER` to `ipc_space_kernel` and `IP_KOBJECT` to `kernel_task`
    5. Set `IE_BITS_SEND` to make it a send right

The Pipe Trick for Determinism: Iterating the `proc` linked list isn’t deterministic and can panic if a process dies mid-iteration. The exploit instead leverages itk_bootstrap—a send right to launchd (pid 1) present in every task struct. Since launchd and kernel_task (pid 0) are adjacent in the `proc` linked list, reading one step backward from launchd yields kernel_task. This approach is fully deterministic and blazing fast.

Pipe-Based Read/Write Primitive: Pipes can be abused to create a powerful kernel read/write primitive:

int p[bash];
pipe(p);
// Write controlled data into pipe 1
// Overwrite pipe 2's pipebuf buffer pointer
// Now pipe 2 reads/writes from arbitrary kernel addresses
// Clean up by restoring the original buffer pointer

5. Achieving Determinism: Under 10ms, 100% Reliability

The final piece of the puzzle is ensuring the exploit never fails. TrigonLegacy achieves this through several innovations:

Seatbelt Trick: The `itk_seatbelt` field in the task struct—normally a send right to sandboxd—can be temporarily swapped with the kernel’s own task port. The kernel happily returns its own task port when asked. This eliminates the need for iterative `proc` list traversal.

Predictable cpu_ttep: As established, cpu_ttep‘s location is entirely deterministic, eliminating the need for unreliable patchfinding.

No Spinlock Panics: By carefully controlling which memory regions are accessed and using the sleep token technique to avoid scanning dangerous areas, the exploit avoids the spinlock panics that plagued earlier attempts.

Results: TrigonLegacy has been executed over 500,000 times in testing—under idle conditions and during CPU-intensive tasks—with zero failures and zero device crashes.

What Undercode Say:

  • The 17-year lifespan of CVE-2023-32434 highlights how even ancient, “obvious” bugs can persist when tunnel vision obscures the actual reachable codepath. The vulnerability wasn’t fixed because researchers focused on the wrong check—a sobering lesson in code review methodology.
  • The exploit’s 100% reliability and sub-10ms execution time demonstrate that deterministic exploitation is achievable even on legacy platforms, provided attackers are willing to combine multiple techniques: physical mapping primitives, sleep token abuse, info leaks, and pipe-based read/write.
  • Apple’s incremental hardening—from tfp0 deprecation in iOS 14 to the introduction of PAN in A10—shows that each generation of mitigations closes specific gaps, but legacy devices remain vulnerable to foundational bugs that predate modern security paradigms.
  • The reuse of CVE-2020-3836 (an info leak) alongside the primary overflow vulnerability underscores the importance of chaining exploits. A single vulnerability is rarely sufficient; modern exploitation requires a toolkit of complementary primitives.
  • The fact that techniques like the sleep token buffer and predictable `cpu_ttep` location remain valid on the latest iOS versions for these devices suggests that Apple’s backwards compatibility efforts sometimes create persistent attack surfaces.

Prediction

  • +1: The publication of TrigonLegacy will spur renewed interest in legacy iOS device security, potentially leading to the discovery of similar ancient bugs that persist in modern XNU codebases through copy-paste inheritance.
  • -1: As Apple continues to phase out support for A7-A9 devices, the practical impact of this exploit will diminish, but it serves as a powerful educational tool for reverse engineers and vulnerability researchers.
  • -1: The 17-year latency of this bug’s discovery and patching raises questions about the effectiveness of Apple’s internal code review processes, particularly for rarely-touched codepaths in the VM layer.
  • +1: The deterministic techniques developed for TrigonLegacy—particularly the use of `itk_bootstrap` to find kernel_task and the abuse of pipes for read/write—will likely be adopted and adapted for exploits targeting other operating systems with similar IPC mechanisms.
  • -1: With tfp0 rendered unusable on iOS 14 and later, the relevance of this specific exploit chain is confined to legacy devices. However, the underlying integer overflow pattern remains a class of vulnerability that continues to plague software across all platforms.

▶️ Related Video (82% Match):

🎯Let’s Practice For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

IT/Security Reporter URL:

Reported By: Aleborges Ios – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeTesting & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky