Motivation
Today I read a very interesting blogpost by Brandon Azad from Google Project 0 (https://googleprojectzero.blogspot.com/2020/11/oops-i-missed-it-again.html) , which disclosed an incorrect bound-check in the function H11ANEInDirectPathClient::externalMethod
, allowing to invoke (more privileged) H11ANEInUserClient
’s external methods in the context of (less privileged) H11ANEInDirectPathClient
, eventually leading to type confusions or other security issues.
It is very likely a copy-paste bug. Similar to Brandon, I also missed the vulnerability! It’s kind of unacceptable. Following Brandon’s blogpost, we will share another bug in the H11ANEIn
driver.
H11ANEIn
The H11ANEIn
driver was first introduced in iOS 12 for A12 devices (e.g., iPhone XS and XS Max). I think that “ANE” stands for “Apple Neural Engine”.
The H11ANEIn
driver offers two types of IOUserClients, H11ANEInDirectPathClient
and H11ANEInUserClient
. In particular, H11ANEInUserClient
is more powerful than H11ANEInDirectPathClient
, as H11ANEInUserClient
has more external methods than H11ANEInDirectPathClient
. However, creating H11ANEInUserClient
requires a special entitlement, com.apple.ane.iokit-user-access
. Only a few executables on iOS have the entitlements, such as aned
and mediaserverd
.
H11ANEInDirectPathClient
Fortunately, the container sandbox allows to open the H11ANEInDirectPathClient
IOUserClient. So third-party apps can open and communicate with H11ANEInDirectPathClient
IOUserClients. Looking at the function H11ANEInDirectPathClient::externalMethod
, (Ok, please forget the incorrect bound-check here), we can find that H11ANEInDirectPathClient
actually has the following interfaces:
- _ANE_DeviceOpen
- _ANE_DeviceClose
- _ANE_ProgramSendRequest
Now let’s take a look at the interface _ANE_ProgramSendRequest
. Function _ANE_ProgramSendRequest
accepts a structural input with length 16.

In fact, at the very beginning of function _ANE_ProgramSendRequest, it would treat the structural input as two uint64 values, and pass them into IOMemoryDescriptor::withAddressRange()
;

Clearly, the first value is a userspace address, and the second value is the length of the userspace buffer. After creating the IOMemoryDescriptor
, _ANE_ProgramSendRequest
continues to call the prepare
and map
functions, and map the memory into the kernel space. In other words, _ANE_ProgramSendRequest
creates a shared memory now.

More importantly, the _ANE_ProgramSendRequest
interface should be called through the IOConnectCallAsyncMethod
function. IOConnectCallAsyncMethod
allows the IOKit extension to asynchronously process requests from the users-pace. By supplying a notification/wakeup port, a user-space program will receive a notification message when the request is done. It implies that the kernel or the extension should store the wakeup port somewhere so that the kernel or the extension can send the notification later.
The vulnerability and exploit
The vulnerability is that, _ANE_ProgramSendRequest
records the notification context, including the port pointer, in the shared memory!

As we can see above, before invoking H11ANEIn::ANE_ProgramSendRequest
, the wakeup port is stored at the shared memory at offset 2616 (note that the offsets vary across iOS kernel versions ).
It’s quite straightforward to convert the vulnerability into an info leak. We can easily get a port pointer in the shared memory after we trigger the execution of H11ANEInDirectPathClient::_ANE_ProgramSendRequest
.
Beyond the info leak, you may have already realized that there are a lot of chances to further exploit the vulnerability, especially for the readers who can still remember the vulnerability exploited by the very first Pangu jailbreak tool (for iOS 7.4.1).
Just a quick recap. At that time, IOSharedDataQueue
stores a mach message header in shared memory. We achieve the kernel exploit by crafting the mach message header (https://googleprojectzero.blogspot.com/2018/10/deja-xnu.html).
Similar here, we can modify the port pointer in the shared memory so that when a notification is to be sent to a fake (arbitrary) port. This blog won’t go to details of the exploit. There are so many different ways to accomplish a kernel exploit when you have a full control to a port pointer.
Things I haven’t mentioned
It wouldn’t be that easy to reproduce the vulnerability, because you will find that H11ANEIn::ANE_ProgramSendRequest
will not deliver a notification to the user-space app unless you have a properly-filled request.
First, H11ANEInDirectPathClient::ANE_DeviceOpen
needs to be executed before H11ANEIn::ANE_ProgramSendRequest
. Second, H11ANEIn::ANE_ProgramSendRequest
will eventually go to the function H11ANEIn::ANE_ProgramSendRequest_gated
.
Both H11ANEInDirectPathClient::ANE_DeviceOpen
and H11ANEIn::ANE_ProgramSendRequest_gated
have a common operation: looking up a program buffer according to a program handle id. This program handle id comes from the user input. Without a correct program handle id, H11ANEIn::ANE_ProgramSendRequest
would simply return. No notification would be sent.
So what is the program buffer and the program handle id? Remember that there is another more privileged IOUserClient, H11ANEInUserClient
. H11ANEInUserClien
t has the interfaces to create and destroy ane programs and get the program handle ids:
- H11ANEInUserClient::_ANE_ProgramCreate
- H11ANEInUserClient:: _ANE_ProgramCreateInstance
- H11ANEInUserClient::_ANE_ProgramDestroy
However, container apps cannot create H11ANEInUserClient
, what can we do?
I had to spend some time on machine learning. It’s true. I learned how to use the Core ML framework (https://developer.apple.com/documentation/coreml), and how to integrate machine learning models into my app. I tried all the models on the page https://developer.apple.com/machine-learning/models/ .
Finally, I figured out that our app can talk to aned
, and then ask aned
to create a H11ANEInUserClient
and create an ane program. After aned
returns a program handle id to my app, we can continue to develop our exploit. So, if you want to reproduce the vulnerability, learn machine learning first!
Thank you for your time.