The external methods IGAccelGLContext::unmap_user_memory and IGAccelCLContext::unmap_user_memory take
an 8 byte struct input which is a user-space pointer previously passed to the equivilent map_user_memory
method.
The Context objects have inline IGHashTable members which store a mapping between those user pointers
and the IGAccelMemoryMap object pointers to which they refer in the kernel. The unmap_user_memory method
calls in order:
::contains
::get
::remove
on the hashmap *before* taking the context's IOLock. This means we can race two threads and by passing them both a valid
mapped user pointer they will both look up the same value in the hash map and return it.
The first exploitable bug is that none of these methods are thread safe; it's quite possible for two threads to be in the
::remove method at the same time and call IOFree on the hash bucket list entry resulting in a double free.
The second bug is that after the call to ::remove although a lock is taken on the Context by this point it's too late; both threads have a pointer to
the same IGAccelMemoryMap which only has one reference. The first thread will call ::release which will free the object, then
the thread will drop the lock, the second thread will acquire it and then use the free'd object before calling ::release again.
This user client code is reachable from many sandboxes including the safari renderer and the chrome gpu process.