Средство очистки адресов с Visual C : игнорирует переполнение буфера чтения, продолжая улавливать переполнение буфера записи

#c #visual-c #buffer-overflow #address-sanitizer

Вопрос:

Рассмотрим следующий пример:

 int main()
{
    char* p = new char[10];
    
    srand(p[11]); // heap buffer overflow - read

    p[11] = rand(); // heap buffer overflow - write
}
 

Я хочу, чтобы ASan пока не помечал heap buffer overflow - read , пока все еще помечал heap buffer overflow - write .

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

Есть ли способ добиться этого?

Ответ №1:

Для достижения этой цели есть два направления.

1. Продолжить после возникновения ошибки

Чтобы продолжить после ошибки, -fsanitize-recover=address следует использовать опцию. Из FAQ:

Вопрос: Может ли средство очистки адресов продолжить работу после сообщения о первой ошибке?

О: Да, это возможно, средство очистки адресов недавно получило режим продолжения после ошибки. Это несколько экспериментально, поэтому может быть еще не таким надежным, как настройка по умолчанию (и не так своевременно поддерживается). Также имейте в виду, что ошибки после первой могут быть ложными. Чтобы включить continue-after-error , скомпилируйте с -fsanitize-recover=address помощью, а затем запустите свой код ASAN_OPTIONS=halt_on_error=0 .

Эта опция еще не поддерживается компилятором MSVC. Существует проблема с его добавлением.

Если бы это сработало, можно было бы установить пользовательский обработчик, который проверял бы, является ли это ошибкой чтения или записи, игнорировал ошибку чтения и сообщал об ошибке записи.

2. Не учитывайте ошибки чтения

Как указал @yugr, есть -mllvm -asan-instrument-reads=false возможность добиться этого. Но эта опция также не поддерживается компилятором MSVC.

Но в некоторых местах все еще есть способ избежать инструментирования компилятора. Так оно и есть __declspec(no_sanitize_address) . Таким образом, цель может быть достигнута путем выделения известных ошибок чтения, например, следующим образом:

 __declspec(no_sanitize_address)
void isolate_read_heap_buffer_overflow(char* p)
{
    srand(p[11]); // heap buffer overflow - read
}

int main()
{
    char* p = new char[10];
    
    isolate_read_heap_buffer_overflow(p);

    p[11] = rand(); // heap buffer overflow - write

    return 0;
}
 

Другая лучшая альтернатива

Есть также clang-cl компилятор, на самом деле это Clang, который поддерживает семантику Visual C . Установщик Visual Studio устанавливает его. Итак, если проект можно перенастроить на использование Clang, это откроет все функции средства очистки адресов, используемые в Clang. К сожалению, перенацеливание некоторой устаревшей кодовой базы может оказаться длительной задачей.

Комментарии:

1. Спасибо — это особенно полезно при работе с SIMD-кодом, поскольку довольно часто чтение за пределами конца буфера, где размер буфера не кратен размеру вектора, и это, как правило, безвредно — мы все равно хотим перехватывать любые векторные записи за пределами конца буфера.

Ответ №2:

Теоретически подача -mllvm -asan-instrument-reads=false в оболочку CL должна отключать инструментирование операций чтения.

Комментарии:

1. Я отредактировал свой ответ, чтобы упомянуть об этом, также я нашел приемлемое решение