
Доказательство концепции для CVE-2023-41992, уязвимости ядра macOS, демонстрирующее методы эксплуатации и содержащее анализ патча.
Это proof-of-concept для CVE-2023-41992. И прежде всего, это не имеет ничего общего с джейлбрейком! И он всё ещё находится в разработке.
Спасибо всем, кто помогал мне до сих пор. Из соображений конфиденциальности я могу не перечислять вас здесь. Напишите мне в личку, если хотите!
Насколько мне известно, патч находится в ipc_right_destroy. Кто-то также указал на это в X (или 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));
Использование ipc_right_destroy для получения записи IPC с типом none, оставшейся в IPC-пространстве, вызовет исключение. Смотрите [0] и [1] ниже.
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] не убьёт задачу в песочнице стороннего приложения. Раньше я выбрал mach_thread_self(), потому что это единственное закреплённое send-право, которое я смог найти.
Но без обхода ReportCrash или SIGKILL эта ошибка будет бесполезна в песочнице WebContent. Поэтому я копнул немного глубже.
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 в ядре обрабатывает исключения защиты портов mach. Для фатального исключения он сначала ищет порт исключений. Если уведомление об исключении возвращает KERN_SUCCESS, выполняется SIGKILL. Выглядит многообещающе: каждая задача, вызвавшая фатальное исключение защиты порта mach, будет убита. Однако...
Фатальные защиты портов Mach - всегда доставляются синхронно.
Я могу просто установить порт исключений потока для потока, который вызывает ошибку, и не обрабатывать уведомление об исключении. Ядро просто будет ждать ответа, без SIGKILL.
Паника в ipc_right_copyout() с NULL-записью.