
Proof-of-concept for CVE-2023-41992, a macOS kernel vulnerability, demonstrating exploitation techniques and providing a patch analysis.
This is a proof-of-concept for CVE-2023-41992. And first of all, this has nothing to do with jailbreak ! And it is still under development.
Thank everyone who helped me so far. For privacy reasons, I may not list you here. DM me if you want !
As far as I know, the patch is in ipc_right_destroy. Someone also pointed this out on X(or Twitter).
diff --git a/osfmk/ipc/ipc_right.c b/osfmk/ipc/ipc_right.c
index a81ac21..32a9a3e 100644
--- a/osfmk/ipc/ipc_right.c
+++ b/osfmk/ipc/ipc_right.c
@@ -912,7 +912,6 @@ ipc_right_destroy(
mach_port_type_t type;
bits = entry->ie_bits;
- entry->ie_bits &= ~IE_BITS_TYPE_MASK;
type = IE_BITS_TYPE(bits);
assert(is_active(space));
Using ipc_right_destroy to get a none type ipc entry left in ipc space would trigger a exception. Check [0] and [1] below.
kern_return_t
ipc_right_destroy(
ipc_space_t space,
mach_port_name_t name,
ipc_entry_t entry,
boolean_t check_guard,
uint64_t guard)
{
...
if (type == MACH_PORT_TYPE_SEND) {
if (ip_is_pinned(port)) {
assert(ip_active(port));
is_write_unlock(space);
mach_port_guard_exception_pinned(space, // <---- [0]
name, port, MPG_FLAGS_MOD_REFS_PINNED_DESTROY);
return KERN_INVALID_CAPABILITY;
}
ipc_hash_delete(space, ip_to_object(port), name, entry);
}
...
if ((type & MACH_PORT_TYPE_RECEIVE) &&
(check_guard) && (port->ip_guarded) &&
(guard != port->ip_context)) {
/* Guard Violation */
uint64_t portguard = port->ip_context;
ip_mq_unlock(port);
is_write_unlock(space);
/* Raise mach port guard exception */
mach_port_guard_exception(name, // <---- [1]
0, portguard, kGUARD_EXC_DESTROY);
return KERN_INVALID_RIGHT;
}
[0] will not kill the task in third party app sandbox. I chose mach_thread_self() before because that is the only pinned send right I could find.
But without avoiding ReportCrash or SIGKILL, the bug won't be helpful in WebContent sandbox. So I dig a little deeper.
void
mach_port_guard_ast(thread_t t,
mach_exception_data_type_t code, mach_exception_data_type_t subcode)
{
...
if (reason <= MAX_FATAL_kGUARD_EXC_CODE) {
/*
* Fatal Mach port guards - always delivered synchronously.
* Check if anyone has registered for Synchronous EXC_GUARD, if yes then,
* deliver it synchronously and then kill the process, else kill the process
* and deliver the exception via EXC_CORPSE_NOTIFY.
*/
if (task_exception_notify(EXC_GUARD, code, subcode) == KERN_SUCCESS) {
task_bsdtask_kill(task);
} else {
exit_with_guard_exception(get_bsdtask_info(task), code, subcode);
}
...
mach_port_guard_ast in kernel handles mach port guard exceptions. For a fatal exception, it first look for exception port. If the exception notify returns KERN_SUCCESS, do a SIGKILL. Looks promising, every task that triggered a fatal mach port guard exception will be killed. However...
Fatal Mach port guards - always delivered synchronously.
I can just set a thread exception port for the thread that trigger the bug, and don't process the exception notification. Kernel will just wait for reply here, no SIGKILL.
Panic in ipc_right_copyout() with a NULL entry.