В iOS 18.4 нашли ошибку, из-за которой приложения вылетают при обычных действиях — Tproger

0
14

В iOS 18.4 обнаружен баг с PAC и dlsym — приложения вылетают при вызове strcmp из-за двойной подписи указателя и сбоя в dyld

Разработчики заметили странный баг в iOS 18.4 — некоторые приложения падают при использовании стандартных функций вроде strcmp.

Причина — критическая ошибка в механизме динамической загрузки символов и работе с Pointer Authentication (PAC) на архитектуре arm64e. А ведь речь идёт о типовом коде с dlopen() и dlsym() — ничего нестандартного.

Вызываешь strcmp() через dlsym, вроде бы получаешь валидный указатель, но при вызове — краш. В системных логах фигурирует KERN_PROTECTION_FAILURE, указывающий на проблему с PAC-подписью указателя.

🔥 Как ФБР взломало Android-смартфон стрелка в Трампа за 40 минутtproger.ru

Ошибка не единичная — повторный запуск воспроизводит падения, а адреса strcmp каждый раз разные, как будто подпись сломана или отсутствует вовсе.

PAC и двойная подпись: что пошло не так

На новых чипах Apple (в частности, A15) используется расширенный механизм PAC из архитектуры Armv8.6-A. В этой версии подпись не заменяет старшие биты указателя, а XOR’ится с ними — что делает поведение более тонким и сложным.

Выяснилось, что в dyld (динамическом загрузчике macOS/iOS) отсутствует важная инструкция XPACI, которая должна была очищать старую подпись перед повторной подписью указателя. В результате символ, полученный через dlsym, оказывается подписан дважды — и система воспринимает его как kernel-указатель. Это приводит к сбою безопасности на уровне ядра и аварийному завершению приложения.

Читать также:
OpenAI, Oracle и SoftBank вложат $500 млрд в развитие ИИ в США — Tproger

Особо интересный момент: strcmp — это не прямая функция, а лениво резолвящийся stub (EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER), который изначально ссылается на функцию __platform_strcmp_ptr в другой библиотеке. Именно на этапе резолвинга и возникает ошибка: dyld получает один раз подписанный указатель и подписывает его снова, не очистив первую подпись.

Почему падает не всё подряд?

Вопрос, который возникает у многих: почему strcpy, загружаемый тем же способом, работает, а strcmp — нет? Ответ — в деталях реализации. У strcpy нет флага ленивого резолвинга, значит вызов не проходит через тот же багованный путь в dyld.

Apple назвала дату презентации iPhone 16 — 9 сентября. Какие новинки покажут на мероприятии?tproger.ru

Ещё один важный момент: стандартный загрузчик обычно использует безопасный режим (Loader::skipResolver), который не активирует резолвер. А вот ручной вызов dlsym() в коде напрямую запускает багованный сценарий.

И да, это настоящая проблема

Проблема воспроизводится стабильно, но только при специфических условиях: arm64e, PAC, использование dlsym, вызов функции с ленивым резолвером. Однако таких случаев может быть гораздо больше, особенно в нативных iOS-приложениях, использующих сторонние библиотеки или плагины.

Пока Apple не выпустила исправление, разработчикам остаётся избегать ленивой загрузки таких символов или вручную пересписывать указатели. Костыльно, но безопаснее.