OS X and iOS kernel UaF/double free due to lack of locking in IOHDIXControllUserClient::clientClose
Here's the clientClose method of IOHDIXControllUserClient on OS X 10.11.1:
__text:0000000000005B38 ; __int64 __fastcall IOHDIXControllerUserClient::clientClose(IOHDIXControllerUserClient *__hidden this)
__text:0000000000005B38 public __ZN26IOHDIXControllerUserClient11clientCloseEv
__text:0000000000005B38 __ZN26IOHDIXControllerUserClient11clientCloseEv proc near
__text:0000000000005B38 ; DATA XREF: __const:000000000000F820o
__text:0000000000005B38 push rbp
__text:0000000000005B39 mov rbp, rsp
__text:0000000000005B3C push rbx
__text:0000000000005B3D push rax
__text:0000000000005B3E mov rbx, rdi
__text:0000000000005B41 mov rax, [rbx]
__text:0000000000005B44 xor esi, esi
__text:0000000000005B46 call qword ptr [rax+600h] ; virtual: IOService::terminate(unsigned int)
__text:0000000000005B4C mov qword ptr [rbx+208h], 0
__text:0000000000005B57 mov qword ptr [rbx+1F8h], 0
__text:0000000000005B62 mov rdi, [rbx+200h] ; <-- this+0x200 --+
__text:0000000000005B69 call _vfs_context_rele ; pass to vfs_context_rele +- should be locked!
__text:0000000000005B6E mov qword ptr [rbx+200h], 0 ; NULL out this+0x200 --+
__text:0000000000005B79 xor eax, eax
__text:0000000000005B7B add rsp, 8
__text:0000000000005B7F pop rbx
__text:0000000000005B80 pop rbp
__text:0000000000005B81 retn
At offset +0x200 the user client has a vfs_context_t (struct vfs_context*) which gets passed to vfs_context_rele:
int
vfs_context_rele(vfs_context_t ctx)
{
if (ctx) {
if (IS_VALID_CRED(ctx->vc_ucred))
kauth_cred_unref(&ctx->vc_ucred);
kfree(ctx, sizeof(struct vfs_context));
}
return(0);
}
This code drop the ref which the context object holds on the credential it holds then it frees the vfs context;
Since there are no locks in the clientClose method two thread can race each other to both read a valid vfs_context_t pointer
before the other one NULLs it out. There are a few possible bad things which we can make happen here; we can double drop the reference
on the credential and double free the vfs_context.
This PoC when run on a machine with -zc and -zp boot args will probably crash doing the double ref drop.
Tested on El Capitan 10.11.1 15b42 on MacBookAir 5,2