kread/kwrite = the ability to read/write arbitrary kernel virtual addresses. This is the primary goal – having kread/kwrite = controlling the kernel.


Why kread/kwrite Is Sufficient

With kread/kwrite you can:

  • Read/write process credentials – get root
  • Modify the sandbox slot – unsandbox
  • Inject trust cache – bypass code signing
  • Read kernel objects – leak additional information
  • Modify any kernel data structure

Techniques

1. IOSurface-Based kread/kwrite

Most common in modern exploits.

Concept:
  IOSurface objects contain dictionary properties (key-value pairs)
  Properties stored as serialized data in the kernel heap
  set_value/get_value methods read/write property data

Exploit:
  1. Create IOSurface
  2. Trigger vulnerability → corrupt IOSurface internal data pointer
  3. iosurface_kread: set corrupted pointer → target address
     → get_value reads from target address → returns data to userspace
  4. iosurface_kwrite: set corrupted pointer → target address
     → set_value writes attacker data to target address

Functions:
  iosurface_kread32(addr)  → read 32 bits at kernel addr
  iosurface_kread64(addr)  → read 64 bits at kernel addr
  iosurface_kwrite32(addr, val) → write 32 bits
  iosurface_kwrite64(addr, val) → write 64 bits

2. Pipe-Based kread/kwrite

Concept:
  pipe() creates a kernel pipe_buffer struct
  read(pipe_fd) reads from pipe_buffer
  write(pipe_fd) writes to pipe_buffer

Exploit:
  1. Create pipe pair
  2. Corrupt pipe_buffer struct:
     - Change buffer pointer → kernel address
     - Change buffer size → large
  3. read(pipe_fd) → kernel copies from corrupted address → kread
  4. write(pipe_fd) → kernel copies to corrupted address → kwrite

3. Fake Task Port (Classic, pre-iOS 14)

Concept:
  task port + mach_vm_read/write = access task's address space
  If task port points to kernel_task → access kernel memory

Exploit:
  1. Craft a fake ipc_port structure in controlled memory
  2. Set kobject type = IKOT_TASK
  3. Set kdata.task → fake task structure
  4. Fake task's map → kernel_map (or kernel_pmap)
  5. Send/receive to get port name for fake port
  6. mach_vm_read(fake_port, addr, size) → kread
  7. mach_vm_write(fake_port, addr, data, size) → kwrite

Mitigated by:
  - PAC on port pointers (iOS 12+)
  - zone_require (iOS 14+)
  - Lockdown of task port operations

4. kfd Methods

The kfd project implements multiple kread/kwrite methods:

Method Mechanism
kread_kqueue_workloop_ctl Abuse kqueue workloop for kernel reads
kread_sem_open Abuse POSIX semaphore for kernel reads
kwrite_dup Abuse dup() file descriptor for kernel writes
kwrite_sem_open Abuse POSIX semaphore for kernel writes

5. Physical R/W → Virtual R/W

If you have physrw (physical read/write):
  1. Read TTBR1_EL1 (kernel page table base) from a known location
  2. Walk kernel page tables manually
  3. Translate kernel virtual address → physical address
  4. Read/write the physical address
  → Equivalent to kread/kwrite but through the physical layer

Stability & Reliability

Method Reliability iOS range Notes
IOSurface High iOS 11+ Standard in modern exploits
Pipe Medium iOS 10+ Simple but has limitations
Fake task port High (when working) iOS ≤13 Killed by PAC + zone_require
kfd methods High iOS 15-16 Well-tested
Physical r/w High Depends Requires PUAF primitive

Resources