H11ANEIn::patchMutableSurface() (reachable from
H11ANEIn::ANE_ProgramSendRequest_gated) is called if the
model.hwx has a mutable procedure and has also initInfo section, I looked for such a model but couldn’t find any, so I ended up patching one of the pre-compiled models and used CVE-2022-32845 to load it. Please keep in mind that CVE-2022-32845 is not required to reach the vulnerable code path from the default app sandbox, it is sufficient to compile a custom mlmodel to achieve the same results. You can find more details about CVE-2022-32845 in my presentation slides.
ZinComputeProgramUpdateMutables() is another function that’s called by
H11ANEIn::patchMutableSurface() and the function prototype is the following:
- init_info: is the
initInfosection that contains a serialized input, you can find the serializer function serialize_initinfo_section() in
weightBufsexploit source code.
- mutable_procedure_info : is a shared IOSurface buffer provided by the attacker, it’s also called weightsBuffer in
- mut_procedure_info_size: It denotes the size of the mutable_procedure_info surface buffer.
- MUTK_kernel_section: (or
MUTK) It’s a mapping buffer of an IOSurface object that’s created by the kernel during program loading phase.
- MUTK_kernel_section_size: is the size of the mutable kernel section.
The loop 88-92 calculates the
MutableWeight object count within the mutable_procedure_info object, then calculates the allocation size of the
MutableWeight array at 93. After that, the
ANECMutableWeight array of objects is allocated at 100, then populated with the appropriate weight buffer/size pair in the loop 111-127 by
ANECGetMutableOperationInfo() returns an object
opsInfo from our shared memory:
ANECGetMutableWeight pseudo-code is the following:
ANECGetMutableWeightInfo pseudo-code is the following:
I already described the format of the
ANECMutableProcedureInfo in “Attacking Apple’s Neural Engine” slides, so feel free to read it if you haven’t already. The structure definition can be found in weightBufs exploit at ‘aneProgram.h’.
If you’ve noticed,
ANECGetMutableOperationInfo()->op_count is fetched twice: once to calculate the size in order to allocate the
ANECMutableWeight array, and once to populate this array.
Because the mutable_procedure_info buffer is a shared memory, an attacker could use a separate thread to change the value of
opsInfo->op_count between the first and the second usages, resulting in a size mismatch that will lead to an interesting OOB write in either a kalloc var zone, kheap defaul or the kernel map.
The vulnerability can be used in many interesting ways. For example, an attacker could set
total_count = 0x1000; at line 93, then increase
opsInfo->count to something larger, causing data to be copied out of bounds at
The kernel will panic at the instruction shown below if the OOB write has reached an unmapped memory area:
This bug provides a strong primitive in that it writes two 64-bit values: a kernel address pointing to our user shared buffer and a (semi-)arbitrary 64-bit value.
The proof-of-concept is left as an exercise for the reader. However,
weightBufs exploit includes everything required to reach the vulenrable code path. Good Luck :-).