Here's a kextd method exposed via MIG(com.apple.KernelExtensionServer)
kern_return_t _kextmanager_unlock_kextload(
mach_port_t server,
mach_port_t client){
kern_return_t mig_result =KERN_FAILURE;if(gClientUID !=0){OSKextLog(/* kext */NULL,kOSKextLogErrorLevel|kOSKextLogIPCFlag,"Non-root kextutil doesn't need to lock/unlock.");
mig_result =KERN_SUCCESS;
goto finish;}if(client !=(mach_port_t)dispatch_source_get_handle(_gKextutilLock)){OSKextLog(/* kext */NULL,kOSKextLogErrorLevel|kOSKextLogIPCFlag,"%d not used to lock for kextutil.", client);
goto finish;}removeKextutilLock();
mig_result =KERN_SUCCESS;
finish:// we don't need the extra send right added by MiGmach_port_deallocate(mach_task_self(), client);return mig_result;}If the client has UID0 but passes an invalid client port this code will
drop a UREF on client port then returnKERN_FAILURE.ReturningKERN_FAILUREinMIG means all resources will be released which will
cause client to be passed to mach_port_deallocate again, even though only
one UREF was taken.You'll have to use a debugger attached to kextd to see this behaviour.Thisclass of bug is exploitable; please see the writeup for mach_portal from 2016whereI exploited a similar issue [https://bugs.chromium.org/p/project-zero/issues/detail?id=959]TheTL;DRis that an attacker can drop an extra UREF on any send rights in kextd for which the
attacker also has a send right; you could use this to cause a name for a privileged service
to be deallocated then cause the name to be reused to name a port you control.Exploitation of this would be a privesc from unentitled root to root with
com.apple.rootless.kext-management and com.apple.rootless.storage.KernelExtensionManagement entitlements,
which at least last time I looked was equal to kernel code execution.
tested on MacOS10.13.2Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/44561.zip