CVE-2025-24257: IOGPUFamily, iOS 18.3.2 to 18.4
This repeats the finding of the
public PoC of CVE-2025-24257,
discovered by Wang Yu of Cyberserval. When a resource group is created with
a capacity under 64, bitmap_mask = (capacity >> 6) - 1 underflows to
0xFFFFFFFF, and the bitmap is read and written out of bounds. iOS 18.4 adds
a check that the capacity is 64 or more.
Get the binaries
$ ipsw download ipsw --device iPhone15,2 --build 22D82 --kernel --output 18.3.2
$ ipsw download ipsw --device iPhone15,2 --build 22E240 --kernel --output 18.4
$ ipsw kernel extract 18.3.2/*/kernelcache.release.iPhone15,2 com.apple.iokit.IOGPUFamily --output 18.3.2
$ ipsw kernel extract 18.4/*/kernelcache.release.iPhone15,2 com.apple.iokit.IOGPUFamily --output 18.4
Compare
$ hereticus --format markdown 18.3.2/com.apple.iokit.IOGPUFamily 18.4/com.apple.iokit.IOGPUFamily
| FUNCTION | CHANGE | SCORE | +/-/~ | TOUCHED | MATCHED BY |
|---|---|---|---|---|---|
sub_fffffff009a95038 -> sub_fffffff009bb22c0 | changed | 0.93 | 96/79/15 | 33 branch, 14 call, 17 jump, 27 mem, 34 const | similar |
| … | |||||
sub_fffffff009a765c0 -> sub_fffffff009b92fa8 | changed | 0.76 | 20/6/3 | 2 branch, 1 call, 1 jump, 4 mem, 3 const, 2 text | similar |
| … |
1728 matched (1304 unchanged, 424 changed), 14 gone, 8 new
43 changed only a constant, hidden. Use –show-retouched to list them.
iOS 18.4 rewrote much of the driver, so 424 functions changed. The fix is row 19.
Find the fix
--diff-all prints every diff in one run, so a search finds the new check:
a compare of a count with 63 or 64.
$ hereticus --diff-all 18.3.2/com.apple.iokit.IOGPUFamily 18.4/com.apple.iokit.IOGPUFamily > diffs.txt
$ awk '/^sub_/{name=$0} /^\+ cmp [wx][0-9]+, #0x(3f|40)$/{print name": "$0}' diffs.txt
sub_fffffff009a765c0 -> sub_fffffff009b92fa8: + cmp w2, #0x3f
...
Read the fix
$ hereticus --diff sub_fffffff009a765c0 18.3.2/com.apple.iokit.IOGPUFamily 18.4/com.apple.iokit.IOGPUFamily
...
- cmp w2, #0x0
...
+ mov x21, x2
+ cmp w2, #0x3f
+ b.hi $+0x40
mov w8, #0x40
- csel w21, w8, w2, eq
...
+ mov w2, #0x11
+ bl $-0x16727c4
+ mov x19, #0x0
+ b $+0x180
...
Before, a capacity of 0 became 64 and any other was taken as given, so a
capacity of 1 to 63 went on to the bitmap. Now a capacity of 63 or less
logs an error and the function returns NULL. The bitmap search that the
mask bounds, sub_fffffff009a83cb0, compares it in 64 bits now too.
--view il shows the two choices plainly: the csel that took 64 for a
capacity of 0, and the branch that now leaves for one of 63 or less.
$ hereticus --view il --diff sub_fffffff009a765c0 18.3.2/com.apple.iokit.IOGPUFamily 18.4/com.apple.iokit.IOGPUFamily
...
- flags = compare(w2, 0)
...
+ x21 = x2
+ flags = compare(w2, 0x3f)
+ if (w2 u> 0x3f) goto $+0x40
w8 = 0x40
- w21 = eq ? w8 : w2
...
+ w2 = 0x11
+ call $-0x16727c4
+ x19 = 0
+ goto $+0x180
...