Почему айфон перезагружается от арабской смс

iago 28 мая 2015 в 14:44 223k
DISCLAIMER

Не пытайтесь повторить это со своими телефонами и телефонами коллег! Судя по комментариям, много людей уже заразили свои телефоны, а 100%-тного лекарства еще нет!

DISCLAIMER 2

Даже не пытайтесь назвать так Wi-fi точку!

Около 15 часов назад на Reddit появился забавный пост, который рассказывал о перезагрузке айфона после странного сообщения вида:
Не шлите никому на айфон
Power
لُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ




Мы с коллегами попробовали и убедились, что это реально работает. Причем работает не обязательно от смс — тексту достаточно было появиться в любом пуш-сообщении.

Конечно же, это не перезагрузка, а крэш графической подсистемы, который вызывает перезагрузку всей системы. Т.к. окно с текстом пуш-сообщения напрямую входит в графическую оболочку iOS, а не является отдельным виджетом (как, например, в Android), логично, что любая ошибка на столь высоком уровне выведет систему из строя.

Также на Reddit было описано лекарство — требуется прислать смс любого содержания на атакованный номер, и глюк пропадет. Поясню — после перезагрузки атакованного телефона все работает нормально до тех пор, пока жертва не хочет прочитать смс, т.е. загрузить встроенное приложение Messages.

Messages вылетает по той же причине, что и вся iOS, с единственной разницей — являясь отдельным приложением, она не провоцирует падение mainthread самой iOS. Крэш Messages происходит из-за того, что на главном экране вы видите тексты последних отправленных и полученных сообщений. После получения нового смс от отправителя «вируса», последним сообщением станет новое смс и Messages, логично, перестанет падать.

Мне стало интересно, почему именно все так печально крешится, и я создал тестовый проект в xCode. При попытке добавить злополучный текст прямо в Interface Builder, я получил крэш самого xCode, причем он не открывался до тех пор, пока я не удалил тестовый проект с жесткого диска.

Со второй попытки я добавлял арабский текст кодом из текстового файла и после нескольких попыток, путем проб и ошибок выяснил, что:
  • UILabel ни при чем, он не может даже показать текст, останавливаясь на слове Power;
  • UITextField аналогично;
  • UITextView прекрасно отобразил полный текст;
  • UIButton сгенерировал bad access!!


Тут уже интересней. Распечатываем полный стэк трейс llvm-командой bt и получаем примерно следующее:

* thread #1: tid = 0xf611cd, 0x00000001120ce5f3 CoreText`CopyFromStorage(TRunGlue&, long) + 28, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x90)
    frame #0: 0x00000001120ce5f3 CoreText`CopyFromStorage(TRunGlue&, long) + 28
    frame #1: 0x00000001120ce283 CoreText`TRunGlue::RotateGlyphs(CFRange, long) + 527
    frame #2: 0x000000011212b71b CoreText`OpenTypeShapingEngine::ApplyScriptShaping(unsigned int*) + 465
    frame #3: 0x00000001120d0201 CoreText`TOpenTypeMorph::ApplyShapingEngine(OTL::GSUB&, OTL::GlyphLookups&, unsigned int*, CFRange, bool&) + 739
    frame #4: 0x00000001120d1007 CoreText`TOpenTypeMorph::ShapeGlyphs(bool&) + 331
    frame #5: 0x0000000112056c4e CoreText`TShapingEngine::ShapeGlyphs(TLine&, TCharStream const*) + 264
    frame #6: 0x000000011205c48b CoreText`TTypesetter::FinishEncoding(std::__1::tuple<TLine const*, TCharStream const*, void const* (*)(__CTRun const*, __CFString const*, void*), void*, std::__1::shared_ptr<TBidiLevelsProvider>*, unsigned int, unsigned char> const&, TLine&, signed char) + 127
    frame #7: 0x0000000112070586 CoreText`TTypesetterAttrString::Initialize(__CFAttributedString const*) + 674
    frame #8: 0x000000011207029a CoreText`TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) + 158
    frame #9: 0x000000011205d79f CoreText`CTLineCreateWithAttributedString + 63
    frame #10: 0x0000000110c6d8bd UIFoundation`__NSStringDrawingEngine + 18744
    frame #11: 0x0000000110c68f5f UIFoundation`-[NSString(NSExtendedStringDrawing) boundingRectWithSize:options:attributes:context:] + 198
    frame #12: 0x000000010e875788 UIKit`-[UIButton _intrinsicSizeWithinSize:] + 946
    frame #13: 0x000000010ec2466d UIKit`-[UIView(UIConstraintBasedLayout) intrinsicContentSize] + 37
    frame #14: 0x000000010ec24b6c UIKit`-[UIView(UIConstraintBasedLayout) _generateContentSizeConstraints] + 33
    frame #15: 0x000000010ec24930 UIKit`-[UIView(UIConstraintBasedLayout) _updateContentSizeConstraints] + 422
    frame #16: 0x000000010ec2bd25 UIKit`-[UIView(AdditionalLayoutSupport) updateConstraints] + 162
    frame #17: 0x000000010e87521b UIKit`-[UIButton updateConstraints] + 2925
    frame #18: 0x000000010ec2b346 UIKit`-[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 242
    frame #19: 0x000000010ec2b53e UIKit`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 124
    frame #20: 0x000000010e0bd354 CoreFoundation`CFArrayApplyFunction + 68
    frame #21: 0x000000010ec2b2ed UIKit`-[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 153
    frame #22: 0x000000010d9ef1be Foundation`-[NSISEngine withBehaviors:performModifications:] + 155
    frame #23: 0x000000010ec2b53e UIKit`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:] + 124
    frame #24: 0x000000010ec2ba0e UIKit`__60-[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded]_block_invoke + 96
    frame #25: 0x000000010d9ef1be Foundation`-[NSISEngine withBehaviors:performModifications:] + 155
    frame #26: 0x000000010ec2b6d6 UIKit`-[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded] + 231
    frame #27: 0x000000010ec2bdde UIKit`-[UIView(AdditionalLayoutSupport) _updateConstraintsAtEngineLevelIfNeeded] + 146
    frame #28: 0x000000010e623a3d UIKit`-[UIView(Hierarchy) _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] + 114
    frame #29: 0x000000010e62fa2b UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 536
    frame #30: 0x0000000111e08ec2 QuartzCore`-[CALayer layoutSublayers] + 146
    frame #31: 0x0000000111dfd6d6 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 380
    frame #32: 0x0000000111dfd546 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 24
    frame #33: 0x0000000111d69886 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 242
    frame #34: 0x0000000111d6aa3a QuartzCore`CA::Transaction::commit() + 462
    frame #35: 0x000000010e5ada2d UIKit`-[UIApplication _reportMainSceneUpdateFinished:] + 44
    frame #36: 0x000000010e5ae6f1 UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 2648
    frame #37: 0x000000010e5ad0d5 UIKit`-[UIApplication workspaceDidEndTransaction:] + 179
    frame #38: 0x0000000110d835e5 FrontBoardServices`__31-[FBSSerialQueue performAsync:]_block_invoke_2 + 21
    frame #39: 0x000000010e0ea41c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame #40: 0x000000010e0e0165 CoreFoundation`__CFRunLoopDoBlocks + 341
    frame #41: 0x000000010e0dff25 CoreFoundation`__CFRunLoopRun + 2389
    frame #42: 0x000000010e0df366 CoreFoundation`CFRunLoopRunSpecific + 470
    frame #43: 0x000000010e5acb42 UIKit`-[UIApplication _run] + 413
    frame #44: 0x000000010e5af900 UIKit`UIApplicationMain + 1282
  * frame #45: 0x000000010d91ed0f Islam`main(argc=1, argv=0x00007fff522e1330) + 111 at main.m:14
    frame #46: 0x000000011076e145 libdyld.dylib`start + 1

Последней документированной функцией является CTLineCreateWithAttributedString, что нам в принципе ничего не дает. Сам же крэш происходит внутри метода CopyFromStorage(TRunGlue&, long) и, судя по ассемблерному коду, в момент копирования байтов длиной long n из одной части памяти в другую (movq 0x90(%rax), %rdx).

Предполагаю, что происходит это из-за каких-то различий в вычислении длины арабского текста — видимо, длина вычисляется в двух местах программы разными методами. Здесь я могу ошибаться и прошу поправить знающих людей.

Баг, видимо, существует столько же, сколько и iOS, и был замечен, видимо, случайно. Кстати, слово Power вставлено для красного словца и роли не играет. Смысл же текста мне не удалось выявить даже с помощью Google Translate (последний символ — вовсе не арабский, а китайский, и означает Избыточность, что как бы намекает!). Возможно, из-за присутствия китайских и арабских символов одновременно?

За сим откланяюсь, желаю всем кодов 200, билдов без exc_bad_access и stackoverflow и приятного окончания продуктивной рабочей недели!
Проголосовать:
+172
Сохранить: