
Proof-of-concept for an out-of-bounds write in XNU's vfs_attr_pack_internal (getattrlist) on iOS 26.6, demonstrating kernel heap corruption and exploitation notes for PAC pointer forging.
vfs_attr_pack_internalComponent: XNU VFS — vfs_attr_pack_internal (getattrlist syscall)
Affected: iOS / iPadOS 26.6 (23G71) and earlier
Fixed in: iOS / iPadOS 26.6.1 (23G83)
Type: Out-of-Bounds write to caller buffer
Impact: Kernel heap corruption; from kernel context (after kernel r/w), enables writing a PAC-signed pointer to an attacker-controlled buffer
Discovered by an anonymous researcher
(per Apple Security Advisory — iOS 26.6.1)
vfs_attr_pack_internal iterates over the requested attribute bitmap and writes each attribute into the caller's buffer sequentially. It does not check whether the running output offset has exceeded bufsize before writing attribute slot 51 (SETXATTR_SLOT).
For a file with a 16-character name, the full valid attribute output is 0x1a4 (420) bytes. Slot 51 starts at offset 0x198 (408 bytes). When the caller supplies a buffer smaller than 0x198 + 8, the kernel writes 8 bytes past the end of the buffer:
; vfs_attr_pack_internal (affected path, 26.6 / 23G71)
; slot 51 write — no bounds check before store
str x_attr_data, [buf + 0x198] ; OOB if bufsize < 0x198 + 8
The valid attribute masks verified by on-device probe (getattrlist on a 16-character filename, iOS 26.6):
| Field | Mask |
|---|---|
commonattr | 0xffe7ffff (bits 19, 20 are invalid on this kernel) |
fileattr | 0x0000363f |
forkattr | 0xffffe003 |
With these masks on a 16-char filename, total output = 0x1a4 bytes. OOB occurs at slot 51 (buf+0x198) whenever bufsize < 0x1a0.
On iOS 26, KHEAP_TEMP isolation prevents the OOB write from directly corrupting adjacent heap allocations in a useful way from userspace. The bug is classified as kernel-heap only in this research:
vfs_attr_pack_internal from a controlled call site.In the iOS 26.6 jailbreak chain, this bug is used in the final stage to write a PACIA-forged pointer into a kernel allocation adjacent to the caller buffer.
poc_getattrlist_oob.c demonstrates the OOB boundary with three calls:
The PoC creates a 16-character filename (/var/root/aaaaaaaaaaaaaaaa) as the test target, runs all three getattrlist() calls, and prints the return codes. A kernel panic log (if triggered) will show a fault at buf+0x198.
/var/root/ write access (for creating the 16-char test file; path can be adjusted to any writable location)# Standalone C binary — no frameworks needed
clang -arch arm64 -o poc poc/poc_getattrlist_oob.c
# For on-device:
clang -arch arm64 -isysroot $(xcrun --sdk iphoneos --show-sdk-path) \
-o poc poc/poc_getattrlist_oob.c
codesign -s "Apple Development" poc
| Date | Event |
|---|---|
| 2026-08-17 | iOS 26.6.1 released with fix |
| 2026-08-17 | Apple credits published in security advisory |
| Call | Buffer size | Expected result |
|---|
| 1 | 64 bytes | Kernel writes 0x1a4 bytes → OOB at buf+0x198 (344 B past end) |
| 2 | 0x198 bytes | OOB write starts exactly at the end of buffer |
| 3 | 0x1a4 bytes | Exact valid size → clean success |