# Фаззинг cppcheck с помощью IJON+AFL

Во время обучения на совместном курсе ФСТЭК России и ИСП РАН по фаззинг-тестированию одним из заданий было проведение фаззинга open-source программы с помощью связки фаззера AFL и механизма аннотаций IJON. Поскольку найти что-либо по данной теме в интернете было достаточно сложно, я решил разбавить тишину описанием своего решения.

Пост ориентирован на людей, похожих по уровню подготовки на меня сейчас - я понимаю, что такое фаззинг и зачем это нужно, но пока не могу сходу решать задачи по фаззингу чего-либо просто смотря на докерфайл и два скрипта по 40 команд. Мне бы хотелось прочитать более подробно описаный процесс фаззинга какого-нибудь ПО и поэтому я решил написать его сам.

Входные данные:

1. Open-source программа на C/C++ входящая в top-200 (посмотреть его можно, например, [здесь](https://github.com/ossf/criticality_score)) - [cppcheck](https://github.com/danmar/cppcheck).
    
2. [IJON](https://github.com/RUB-SysSec/ijon) - механизм создания аннотаций, которые помогают направлять фаззер AFL, который включен в репозиторий IJON.
    
3. Задача - провести фаззинг-тестирование cppcheck, определив интересующие состояния программы и создав для этих состояний аннотации с помощью IJON.
    

В результате работы мы:

* Сориентируемся, как работает cppcheck
    
* Подготовим набор входных данных с помощью генератора программ на C
    
* Соберем IJON и фаззер
    
* Соберем cppcheck с инструментацией
    
* Запустим фаззинг cppcheck с IJON в 4 потока
    
* Посмотрим на результаты деятельности
    

# Изучаем cppcheck

Для начала постараемся быстро понять, как работает попавшаяся нам программа - cppcheck. Создадим в домашней папке директорию kuzz (kuznetsov + fuzz, очень оригинально, да) и скопируем туда файлы cppcheck

```bash
ubuntu@ubuntu:~$ mkdir kuzz 
ubuntu@ubuntu:~$ cd kuzz ubuntu@ubuntu:~/kuzz$ git clone https://github.com/danmar/cppcheck.git --single-branch --depth=1 cppcheck_simple 
ubuntu@ubuntu:~/kuzz$ cd cppcheck_simple/
```

Собираем с помощью make.

```bash
ubuntu@ubuntu:~/kuzz$ make
```

Теперь читаем [мануал](https://cppcheck.sourceforge.io/manual.pdf) и узнаем, как же работает программа. Узнаем, что на вход она получает файлы с кодом на C++ и потом их анализирует. Значит легитимными входными данными, которые мы будем подавать на вход фаззеру должны быть файлы с кодом на C++. Остается найти какое-то количество таких файлов.

# Собираем входные данные

Для подготовки входных данных воспользуемся программой [csmith](https://github.com/csmith-project/csmith), которая генерирует программы на C. Установим csmith, предварительно установив cmake и m4 согласно документации:

```bash
ubuntu@ubuntu:~/kuzz$ sudo apt install cmake m4
ubuntu@ubuntu:~/kuzz$ git clone https://github.com/csmith-project/csmith.git --single-branch --depth=1 
ubuntu@ubuntu:~/kuzz$ cd csmith/ 
ubuntu@ubuntu:~/kuzz/csmith$ cmake . 
ubuntu@ubuntu:~/kuzz/csmith$ make 
ubuntu@ubuntu:~/kuzz/csmith$ sudo make install
```

Теперь создадим папку "in" для входных данных, куда положим 10 сгенерированных csmith файлов:

```bash
ubuntu@ubuntu:~/kuzz/csmith$ cd .. 
ubuntu@ubuntu:~/kuzz$ mkdir in ubuntu@ubuntu:~/kuzz$ cd in 
ubuntu@ubuntu:~/kuzz/in$ for i in {1..10}; do csmith > random"${i}".cpp; done
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675152366045/81150641-c6d4-4571-9e18-1d7b093e28af.jpeg align="center")

Попробуем подать один из этих файлов на вход нашей cppcheck

```bash
ubuntu@ubuntu:~/kuzz$ cd ~/kuzz/cppcheck_simple/
ubuntu@ubuntu:~/kuzz/cppcheck_simple$ ./cppcheck ../in/random1.cpp
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675153157913/b95515ac-8859-423f-8f02-bb35d27be76a.jpeg align="center")

Как видим, cppcheck проверил наш файл и не обнаружил ошибок. Теперь нужно определить, какое состояние программы мы будем считать интересным настолько, чтобы написать к нему аннотацию для IJON.

# Собираем IJON

IJON не обновлялся достаточно давно, поэтому могут быть различные проблемы, но в общем процесс в соответствии с документацией выглядит так (у меня, например, не было рекомендованного 6-го clang, поэтому пришлось его поставить).

```bash
ubuntu@ubuntu:~/kuzz$ git clone https://github.com/RUB-SysSec/ijon ubuntu@ubuntu:~/kuzz$ cd ijon/ 
ubuntu@ubuntu:~/kuzz/ijon$ make 
ubuntu@ubuntu:~/kuzz/ijon$ cd llvm_mode/ 
ubuntu@ubuntu:~/kuzz/ijon/llvm_mode$ sudo apt install clang-6.0 
ubuntu@ubuntu:~/kuzz/ijon/llvm_mode$ LLVM_CONFIG=llvm-config-6.0 CC=clang-6.0 make
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675151635365/e3feb8d9-7804-4dd9-b6da-ab7a2459e502.jpeg align="center")

Фаззер готов.

# Пишем аннотацию под IJON

Для начала сделаем новую копию репозитория, с еще не собранными исходными кодами:

```bash
ubuntu@ubuntu:~/kuzz$ git clone https://github.com/danmar/cppcheck.git --single-branch --depth=1 
ubuntu@ubuntu:~/kuzz$ cd cppcheck/lib 
ubuntu@ubuntu:~/kuzz/cppcheck/lib$ ls
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675153189088/2fe668b4-2526-4dd9-80b8-9cf18d311415.jpeg align="center")

Как видно, cppcheck состоит из достаточно большого количества файлов. Быстро пробежавшись по ним, определяемся с тем, что представляется интересным. Поскольку cppcheck это по сути статический анализатор кода, его предназначение - находить ошибки. Поскольку мы хотим добиться покрытия большего количества кода cppcheck (одна из целей фаззинга изначально), то нам интересно, чтобы ошибки находились как можно чаще. В этом нам может помочь IJON, если мы установим аннотацию, которая будет направлять фаззер в сторону увеличения количества ошибок в генерируемых файлах. Механизм вывода уведомлений о найденных ошибках описан в файле errorlogger.cpp. Откроем его с помощью vim.

```bash
ubuntu@ubuntu:~/kuzz/cppcheck/lib$ vim errorlogger.cpp
```

Разные ошибки вызывают разные функции, но есть то, что их объединяет - вывод уведомления об ошибках setmsg.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675152469960/0881e117-865b-4926-80c0-a9693d24f2a2.jpeg align="center")

Чем чаще вызывается вывод уведомления об ошибках, тем больше (логично) ошибок было найдено, а это как раз то, что нам и нужно. Аннотацию IJON можно было бы "прицепить" к существующей переменной, но поскольку таких нет, то придется сделать свою переменную, которая будет считать количество обращений к этой функции. По рекомендации со [stackoverflow](https://stackoverflow.com/questions/3041329/c-keep-track-of-times-function-is-called) добавляем к этой функции статическую переменную, подсчитывающую количество обращений. А потом добавляем аннотацию IJON, которая будет направлять фаззер в сторону увеличения значения этой переменной.

Здесь следует сказать, что мы будем использовать именно максимизирующую аннотацию IJON\_MAX(), о других аннотациях можно прочитать в README IJON, но стоит иметь ввиду, что аннотации IJON\_ENABLE() и IJON\_DISABLE() из коробки не работают (спасибо Дмитрию Пономареву за это замечание).

```cpp
static unsigned int call_count = 0;
    call_count++;
IJON_MAX(call_count);
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675152609672/f36633d8-b319-4476-b58e-0d0a8d84caed.jpeg align="center")

# Собираем проект с инструментацией

Для того, чтобы собрать проект с инструментацией фаззера нужно проделать ту же команду make, только вместо стандартных компиляторов указать компиляторы, находящиеся в папке IJON.

```bash
ubuntu@ubuntu:~/kuzz/cppcheck/lib$ cd .. 
ubuntu@ubuntu:~/kuzz/cppcheck$ CC=/home/ubuntu/kuzz/ijon/afl-clang-fast  CXX=/home/ubuntu/kuzz/ijon/afl-clang-fast++ cmake .
ubuntu@ubuntu:~/kuzz/cppcheck$ CC=/home/ubuntu/kuzz/ijon/afl-clang-fast  CXX=/home/ubuntu/kuzz/ijon/afl-clang-fast++ make
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675152698891/dbf9fc63-6325-4396-be14-e3f7a3304d83.jpeg align="center")

# Фаззинг

После того как завершена сборка с инструментацией можно наконец запустить фаззинг.

```bash
ubuntu@ubuntu:~/kuzz/cppcheck$ cd ../ijon/ 
ubuntu@ubuntu:~/kuzz/ijon$ ./afl-fuzz -i /home/ubuntu/kuzz/in -o /home/ubuntu/kuzz/out -M fuzzer01 -- /home/ubuntu/kuzz/cppcheck/bin/cppcheck @@
```

Появляется стандартная ошибка, в тексте которой сразу указано, что нужно исправить:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675152788043/d701f4cf-b574-48d7-abc5-55d9cf41bd52.jpeg align="center")

```bash
ubuntu@ubuntu:~/kuzz/ijon$ sudo su 
root@ubuntu:/home/ubuntu/kuzz/ijon# echo core >/proc/sys/kernel/core_pattern 
root@ubuntu:/home/ubuntu/kuzz/ijon# exit 
ubuntu@ubuntu:~/kuzz/ijon$ ./afl-fuzz -i /home/ubuntu/kuzz/in -o /home/ubuntu/kuzz/out -M fuzzer01 -- /home/ubuntu/kuzz/cppcheck/bin/cppcheck @@
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675152817738/d36a2b81-3cf0-4946-9a7f-e031b082427d.jpeg align="center")

Как мы могли заметить и ранее, cppcheck анализирует программы достаточно долго. Это усугубляется тем, что сгенерированные csmith тексты программ достаточно объемные, поэтому за установленную 1 секунду cppcheck может не успевать обработать входной сэмпл. Попробуем увеличить время обработки до 4 секунд и добавить знак "+", чтобы разрешить пропуск входных сэмплов по таймауту.

```bash
ubuntu@ubuntu:~/kuzz/ijon$ ./afl-fuzz -i /home/ubuntu/kuzz/in -o /home/ubuntu/kuzz/out -M fuzzer01 -t 4000+ -- /home/ubuntu/kuzz/cppcheck/bin/cppcheck @@
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675152957440/4494a5d3-99d0-41fe-b0a4-20c6551d2372.jpeg align="center")

Как видим, часть тестов пропущена, но для нашей задачи это не принципиально. Теперь фаззинг запущен в одном потоке, откроем новые окна терминала и запустим в них параллельные потоки

```bash
**открываем новое окно терминала**
ubuntu@ubuntu:~/kuzz/ijon$ ./afl-fuzz -i /home/ubuntu/kuzz/in -o /home/ubuntu/kuzz/out -S fuzzer02 -t 4000+ -- /home/ubuntu/kuzz/cppcheck/bin/cppcheck @@ 
**открываем новое окно терминала**
ubuntu@ubuntu:~/kuzz/ijon$ ./afl-fuzz -i /home/ubuntu/kuzz/in -o /home/ubuntu/kuzz/out -S fuzzer03 -t 4000+ -- /home/ubuntu/kuzz/cppcheck/bin/cppcheck @@ 
**открываем новое окно терминала**
ubuntu@ubuntu:~/kuzz/ijon$ ./afl-fuzz -i /home/ubuntu/kuzz/in -o /home/ubuntu/kuzz/out -S fuzzer04 -t 4000+ -- /home/ubuntu/kuzz/cppcheck/bin/cppcheck @@
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675153030882/88d7a495-a7e5-4cc0-9f92-d0e94898b7c1.jpeg align="center")

Поскольку cppcheck достаточно долго обрабатывает файлы, то количество выполнений не выглядит сильно ужасающим, хотя AFL и считает, что раз у нас меньше 100 запусков - мы slow. Посмотрим, получилось ли добиться каких-то результатов именно благодаря использованию IJON.

```bash
ubuntu@ubuntu:~/kuzz/ijon$ cd /home/ubuntu/kuzz/out/fuzzer01/ijon_max/ ubuntu@ubuntu:~/kuzz/out/fuzzer01/ijon_max$ ls
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675153080401/1e8cff9a-6ab1-403a-b11b-f1aef496ffa9.jpeg align="center")

Как видим, папка ijon\_max не пуста, следовательно есть результаты работы механизма аннотаций

# Заключение

Выполнение задания было ограничено по времени, если бы его было больше, то можно было бы:

1. Собрать покрытие кода (например с помощью llvm-cov), которое скорее всего было бы достаточно низким за то время, которое был запущен фаззер. Поскольку генерировать требуется программы на языке C с достаточно сложным синтаксисом, то для фаззинга нужны гораздо большие мощности и время.
    
2. Определить другие состояния программы и установить аннотации IJON и на них тоже.
    

В целом использование аннотаций IJON кажется очень актуальным для фаззинга в ситуациях, когда нужно максимизировать какую-либо координату (это очень хорошо видно на примере фаззинга игр, но это скорее удобный способ демонстрации, чем реальное применение). Подробнее о возможных способах применения IJON можно прочитать в [оригинальной научной публикации разработчика](https://ieeexplore.ieee.org/document/9152719). Чтобы оценить, были ли аннотации полезны в данном задании требуется гораздо больше времени и мощностей для фаззинга.

Буду рад вашим комментариям и замечаниям к тому, что можно и нужно сделать лучше или по-другому. Отдельно хочется сказать большое спасибо коллективу ИСП РАН за проведение данного курса, команде Crusher и отдельно Виталию и Дмитрию за помощь и рекомендации по подготовке этого поста. Всем удачного фаззинга :)
