NX-бит: не только защита, но и причина загадочных сбоев

The NX bit is not just about security

В гостевом посте Соня рассказывает, как при разработке гипервизора для ARM64 на MediaTek MT6735 столкнулась с необъяснимыми зависаниями при перехвате регистра CTR_EL0. Методом бинарного биссектрирования она выяснила, что проблема возникает только при динамическом вызове функции через blr, а не при статическом bl. Разгадка оказалась в спекулятивном исполнении: предсказатель переходов мог угадать адрес 0x0, что приводило к сбою. Это демонстрирует, что NX-бит, запрещающий исполнение кода в неисполняемых областях, защищает не только от атак, но и от подобных микроархитектурных ошибок.

Как динамические вызовы отличаются от статических? Динамические используют предсказание переходов, статические знают, куда ведут, заранее и не могут ошибиться в предсказании.
  1. repiret

    "Спекулятивная выборка инструкций из памяти устройства приводит к сбою устройства" — в моём списке любимых багов. Я столкнулся с этим на Cortex-M4 без MPU, так что не мог даже исправить атрибуты памяти, единственным решением было перекроить скомпилированный код, чтобы предотвратить спекулятивную выборку.

    Безумие, что Armv8/9-A допускает спекулятивную выборку инструкций из памяти устройства. Настолько безумно, что мне пришлось искать это, чтобы поверить:

    "Аппаратное обеспечение не предотвращает спекулятивную выборку инструкций из области памяти с любыми атрибутами Device, если эта область также не помечена как execute-never для всех уровней исключений." — ARM DDI 0487K.a § B2.15.2

    Спецификация Armv7-M менее ясна. В ней говорится: "Архитектура не допускает спекулятивных обращений к памяти, помеченной как Device", в отличие от Armv8/9-A, где аналогичное утверждение уточняется "обращения к данным". Но затем говорится: "Для обеспечения корректности места, чувствительные к чтению, должны быть помечены как неисполняемые". (Это всё из ARM DDI 0403E.e § A3.5.7)

    У меня нет под рукой более старой версии v7-A, чтобы сравнить, что там сказано.

  2. asveikau

    В продолжение темы, что дело не только в безопасности: если у вас есть баг вроде use-after-free, и он случайно затрагивает указатель на функцию, бит NX может гарантировать, что при переходе по этому указателю вы получите чистое исключение как можно ближе к точке сбоя. Если бы он вслепую исполнял устаревшие байты как код, возможно, сбой и стек-трейс выглядели бы не так красиво.

    Но и многие подобные баги корректности также являются проблемами безопасности.

  3. anyfoo

    В наши дни считается дурным тоном отображать что-либо по адресу 0... теперь вы знаете одну из причин!

    В известном мне случае с тождественным отображением адресного пространства 1:1 физическое адресное пространство на самом деле тоже не содержит ничего по адресу 0, так что отображать его всё равно не нужно.

  4. mubbicles

    Я оценил эту статью. Я спрашивал нашего специалиста по CSP о разнице, но это помогает мне лучше понять разницу между device и ns. Также ценю, что это не выглядит написанным ИИ.

  5. eqvinox

    Честно говоря, это похоже на ошибку проектирования в ARM. Где вообще имеет смысл, чтобы память Device не допускала предварительную выборку данных, но допускала предварительную выборку инструкций? По моему мнению, она должна запрещать любую предварительную выборку...

Ещё за этот день

2026-09-07