Инструменты clang AddressSanitizer неправильно кодируют, ложноположительный результатC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Инструменты clang AddressSanitizer неправильно кодируют, ложноположительный результат

Сообщение Anonymous »

Предисловие
Этот вопрос чертовски обширен и связан с моей магистерской диссертацией, поэтому я смиренно прошу вашего терпения. Около полугода назад я столкнулся с проблемой, о которой буду рассказывать дальше, и проблема требовала внешнего взгляда, потому что в тот момент я действительно застрял, и мне некому было помочь. В конце концов я махнул рукой на проблему, но теперь снова в деле (второе дыхание, скажем так).
ВВЕДЕНИЕ
Важнейшие технологии, использованные в проекте:
C++, llvm/clang 13.0.1, ASAN, libFuzzer
Основная идея проекта, который я писал это:
  • Написать парсер проектов C-code для поиска функций, которые предположительно уязвимы (в рамках текущего вопроса не имеет значения, как я решу, что они уязвимы)
  • Когда я нахожу уязвимую функцию, я начинаю писать код фаззера с помощью libFuzzer для этой функции.
  • На этом этапе у меня есть IR-файл с моей уязвимой функцией, IR-файл с мой код фаззера, так что пришло время
    выполнить отдельную компиляцию двух файлов. В процессе компиляции я снабжаю их ASAN и libFuzzer с помощью компилятора clang.
  • Таким образом, два файла объединяются, и у меня есть исполняемый файл, называемый, например, «fuzzer». Теоретически я могу выполнить этот исполняемый файл, и libFuzzer собирается фаззить мою уязвимую функцию.
АКТУАЛЬНАЯ ПРОБЛЕМА (ЧАСТЬ 1)
ASAN как-то плохо инструктирует мой код. Это дает мне неправильный результат.
Откуда я это знаю?
Я нашел и воспользовался уязвимой функцией. Эта функция взята из старой версии libcurl и называется sanitize_cookie_path. Я воспроизвел ошибку с помощью AFL++, и это дало мне то, что я хотел. Если вы передадите в функцию одинарную кавычку, она «взорвется». Нечто подобное я хотел сделать с libFuzzer и ASAN, но, как я уже говорил ранее, эти два не дали мне ожидаемого результата. Потратив некоторое время на проблему, могу сказать, что с ASAN что-то есть.
ВОСПРОИЗВЕДЕНИЕ ПРОБЛЕМЫ
  • Код (см. ниже) у меня есть в файле sanitize_cookie_path.c:

    Код: Выделить всё

     #include 
    #include 
    #include 
    #include 
    #include 
    
    static char* sanitize_cookie_path(const char* cookie_path) {
    size_t len;
    char* new_path = strdup(cookie_path);
    if (!new_path) {
    return NULL;
    }
    
    if (new_path[0] == '\"') {
    memmove((void *)new_path, (const void*)(new_path + 1), strlen(new_path));
    }
    if (new_path[strlen(new_path) - 1] == '\"') {
    new_path[strlen(new_path) - 1] = 0x0;
    }
    
    if (new_path[0] !='/') {
    free(new_path);
    new_path = strdup("/");
    return new_path;
    }
    
    len = strlen(new_path);
    if (1 < len && new_path[len - 1] == '/') {
    new_path[len - 1] = 0x0;
    }
    
    return new_path;
    }
    
    int main(int argc, char** argv) {
    if (argc != 2) {
    exit(1);
    }
    
    sanitize_cookie_path('\"');
    
    return 0;
    }
    
  • Мой код C++ компилирует его с помощью команды:

    Код: Выделить всё

    clang -O0 -emit-llvm path/to/sanitize_cookie_path.c -S -o path/to/sanitize_cookie_path.ll > /dev/null 2>&1
    
  • На уровне IR приведенного выше кода я избавляюсь от «main», поэтому присутствует только функция «sanitize_cookie_path».
  • Я генерирую простой код фаззера (см. ниже) для этой функции:

    Код: Выделить всё

    #include 
    #include 
    
    static char* sanitize_cookie_path(const char* cookie_path) ;
    
    extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    (void) sanitize_cookie_path((char*) data);
    
    return 0;
    }
    
  • Затем я компилирую его командой:

    Код: Выделить всё

    clang -O0 -emit-llvm path/to/fuzz_sanitize_cookie_path.cc -S -o path/to/fuzz_sanitize_cookie_path.ll > /dev/null 2>&1
    
  • Два IR-файла компилируются отдельной компиляцией. ЗАМЕТЬТЕ, что перед отдельной компиляцией я выполняю некоторые действия, чтобы они соответствовали друг другу. Например, я отказываюсь от ключевого слова static и разрешаю искажение имен из кода C++ в код C.
  • Я компилирую их оба вместе с помощью команды:

    Код: Выделить всё

    clang++ -O0 -g -fno-omit-frame-pointer -fsanitize=address,fuzzer -fsanitize-coverage=trace-cmp,trace-gep,trace-div path/to/sanitize_cookie_path.ll path/to/fuzz_sanitize_cookie_path.ll -o path-to/fuzzer > /dev/null 2>&1
    
  • Окончательный исполняемый файл фаззера готов.
АКТУАЛЬНАЯ ПРОБЛЕМА (ЧАСТЬ 2)
Если вы запустите программу фаззера, она не даст вам таких же результатов, как AFL++. Мой фаззер падает на функцию __interceptor_strdup из какой-то стандартной библиотеки (см. фрагмент ошибки ниже). Отчет о сбое, сделанный libFuzzer, буквально пустой (0 байт), но в идеале он должен был обнаружить, что ошибка связана с кавычкой ("). Проведя собственное исследование, я обнаружил, что ASAN неправильно инструментировал код, и это дает мне результат ложной позиции. Честно говоря, я могу фаззить функцию printf из stdio.h и найти ту же ошибку.

Код: Выделить всё

[sanitize_cookie_path]$ ./fuzzer
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 1016408680
INFO: Loaded 1 modules   (11 inline 8-bit counters): 11 [0x5626d4c64c40, 0x5626d4c64c4b),
INFO: Loaded 1 PC tables (11 PCs): 11 [0x5626d4c64c50,0x5626d4c64d00),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
=================================================================
==2804==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000011 at pc 0x5626d4ba7671 bp 0x7ffe43152df0 sp 0x7ffe431525a0
READ of size 2 at 0x602000000011 thread T0
#0 0x5626d4ba7670 in __interceptor_strdup (/path/to/fuzzer+0xdd670)
#1 0x5626d4c20127 in sanitize_cookie_path (/path/to/fuzzer+0x156127)
#2 0x5626d4c20490 in LLVMFuzzerTestOneInput (/path/to/fuzzer+0x156490)
#3 0x5626d4b18940 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/path/to/fuzzer+0x4e940)
#4 0x5626d4b1bae6 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector&) (/path/to/fuzzer+0x51ae6)
#5 0x5626d4b1c052 in fuzzer::Fuzzer::Loop(std::vector&) (/path/to/fuzzer+0x52052)
#6 0x5626d4b0100b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/path/to/fuzzer+0x3700b)
#7 0x5626d4af0297 in main (/path/to/fuzzer+0x26297)
#8 0x7f8e6442928f  (/usr/lib/libc.so.6+0x2928f)
#9 0x7f8e64429349 in __libc_start_main (/usr/lib/libc.so.6+0x29349)
#10 0x5626d4af02e4 in _start /build/glibc/src/glibc/csu/../sysdeps/x86_64/start.S:115
Я использовал GDB для входа в strdup(cookie_path). gdb показывает мне, что фаззер валится по адресу 0x0000555555631687.

Код: Выделить всё

0x0000555555631684 :  mov    %rbp,%rsi
0x0000555555631687 :  addr32 call 0x555555674100 
0x000055555563168d :  pop    %rax
ЧТО Я ПЫТАЛСЯ СДЕЛАТЬ
  • Я пытался инструментировать свои sanitize_cookie_path.c и fuzz_sanitize_cookie_path.cc с помощью ASAN в самом начале, не на уровне IR, но что бы я ни делал, ничего не получалось.
  • Я перешел к так называемому «фаззеру» каталог corpus с предварительно подготовленными данными для передачи в фаззер. Я даже явно передал цитату «фаззеру», но ничего. Пример (с тем же каталогом, что и фаззер):

    Код: Выделить всё

    $ mkdir corpus/; echo "\"" > corpus/input; hexdump corpus/input
    0000000 0a22
    0000002
    $ ./fuzzer corpus/
    
  • Я также погуглил все, что мог, о libFuzzer и ASAN, но ничего не дало результатов.
  • Изменил команду компиляции. Я избавился от '-fno-omit-frame-pointer' и '-fsanitize-coverage=trace-cmp,trace-gep,trace-div'.
Если в предоставленных мной деталях есть какие-то неточности, не стесняйтесь спрашивать о них, и я исправлю их, чтобы вам было более понятно.
Что еще есть? сайты/форумы, где меня могут услышать? В идеале я бы хотел связаться с разработчиками ASAN.
Буду более чем рад любой помощи.
ОБНОВЛЕНИЕ 10.04.2022
llvm/clang был обновлен с 13.0.1 до последней доступной версии в репозитории Arch - 14.0.6. Проблема по-прежнему сохраняется.
Открыл проблему в репозитории google/sanitizers.

Подробнее здесь: https://stackoverflow.com/questions/739 ... ive-result
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»