01.05 Позитивные технологии
01.05 Позитивные технологии
01.05 Позитивные технологии

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

Новости

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Следите за новыми постами
Следите за новыми постами по любимым темам
110 открытий3К показов