It turned out that yes, there were other bugs.
One of them I found, which had maybe some chances of being exploitable on OS X without
SMAP, was patched in
In this post I will discuss one of the other unexploitable null pointers I disclosed to Apple after the
10.11.4 release, because surprisingly even after 2 very similar bugs fixed, Apple failed to eliminate all of them.
Those bugs can be pretty annoying, since they can at least panic the kernel from any context and sandbox.
Unfortunately on OS X, unlike other Operating Systems, kernel NULL pointers are still a problem if your machine doesn’t support
SMAP, since the NULL page under certain circumtances can be mapped, and if the bug allows it (like Luca’s tpwn kernel NULL pointer), it can be exploited.
Checkout Ian Beer’s issues in the Project Zero tracker for additional details.
MIG and IKOT_TASK:
Without going too much in details, since there are very good articles (from J Levin) onlines and books (the ones from Levin again and the one from Amit Singh), and as I mentioned, checkout Luca’s presentation. I will also take some shortcuts and use a more “free” language and try to explain the concepts instead of all the details, which you can eventually check in the code or in the mentioned references:
- MIG is a OS X / iOS IPC “higher level facility” of interfaces built upon mach messages and mach ports used to communicate between tasks, including with the kernel.
- MIG systems exports a well defined interface of methods you can remotely invoke.
- Those methods have a signature and parameters types. Since only some “primitive” parameters are understood by the IPC system, some of them must be validated and converted. The root cause of the bug resides in this last statement.
- What’s IKOT_TASK then? To understand this bug you just have to know that it’s a “type” of mach port. They are all mach ports but there are different flavors depending on what they represent. For example if you call
mach_task_self()you get back a port of kind “task” if you call
mach_thread_self()you get back a port of kind “thread”.
One of the bugs
Take a look at this simple kernel method, which you can invoke from userspace with MIG like we said:
Notice that the first parameter it’s of type
This type is not a “primitive” type, in a MIG sense, so it has to be converted. You can see this in the MIG interface definition file
task.defs with this procedure:
task_t is defined in another
mach_types.defs file with the conversion function to convert it from a
So we have to check the “intran” (translator function from the
mach_port_t received to a
As you can see this function can potentially return a NULL pointer (
TASK_NULL) if the mach_port we pass to it it’s not of
IKOT_TASK. Even the comment says it can return a NULL.
But read then again the
As you can see there is no check if the parameter is null or not, so if it’s null we will crash in a read access from NULL page at:
The bug it’s totally useless, but anyway I wanted to share this writeup to show to you that sometimes when a bug is fixed, other very similar bugs are still present in the code and unfixed. And also offers a quick tour of the MIG interface to the kernel.
As you can see we pass to
mach_thread_self() which is not
IKOT_TASK, triggering the null pointer.
The correct use (without the bug) of this API is to pass a
mach_task_self() or another task port.
- 2016/3/23 The issues are reported to Apple via email at
email@example.com 90 days responsible disclosure policy.
- 2016/5/27 Apple told me even if it’s not fixed in 10.11.5, the fix it’s scheduled for the next release, so holding public disclosure.
- 2016/7/17 CVE-2016-1865 is assigned and the fix is pushed in 10.11.6
- Sometimes vendors just fix the immediate problem and bug, and don’t investigate carefully about the root cause and search for additional bugs that share the same pattern.