# Запуск фаззера на один раунд ###### tags: `fuzzer`, `run` ## Создание сессии Файл реализации - [`fuzz_task.py`](https://github.com/google/clusterfuzz/blob/master/src/python/bot/tasks/fuzz_task.py) Для запуска фаззера используется класс `FuzzingSession` ![](https://i.imgur.com/vEOwaHl.png) В качестве аргументов в конструктор класса `FuzzingSession` передаются: - `fuzzer_name` - Имя фаззера (libfuzzer, afl, ...) - `job_name` - Название доп. тулзы/санитайзера (HWASAN, ASAN, CFI, MSAN, TSAN, UBSAN) - `test_timeout` - Максимальное время, через которое процесс фаззера должен быть убит ## Обновление компонентов Все бинарные компоненты и скрипты хранятся в Google Cloud Storage (GCS). Для обновления компонентов необходимо скачать оттуда архив и распаковать его в соответствующую папку ### Обновление fuzzing engine Сначала обновляются необходимые компоненты фаззера (fuzzing engine). Обновлённая версия скачивается и распаковывается в папку его установки. За это отвечает функция [`update_fuzzer_and_data_bundles`](https://github.com/google/clusterfuzz/blob/master/src/python/bot/tasks/setup.py#L465). ### Обновление фаззеров После обновления основых компонентов проверяется наличие обновлённых бинарников в GCS. Процессы скачивания бинарников, настройки переменных среды, выбора нового фаззера для запуска в clusterfuzz осуществляются функцией [`setup_build`](https://github.com/google/clusterfuzz/blob/master/src/python/build_management/build_manager.py#L1397). В ней вычисляется тип сборки: *Custom*, *Funcsia*, *Regular*, *RemoteRegular*. Затем вызывается соотвествующий конструктор класса. После этого вызывается метод класса `setup`, осуществляющий вышеперечисленные действия. ![](https://i.imgur.com/FvnMXk2.png) В процессе сборки (setup build) существуют следующие этапы: - Скачивание архива с фаззерами - Выбор нового фаззера для запуска - Установка переменных среды В [`_unpack_build`](https://github.com/google/clusterfuzz/blob/master/src/python/build_management/build_manager.py#L464) осуществляются первые два этапа. Скачивается архив с фаззерами (если локально нет файлов с этой ревизией) и распаковывается в *build_dir*. Далее из *build_dir* функцией [`_set_random_fuzz_target_for_fuzzing_if_needed`](https://github.com/google/clusterfuzz/blob/master/src/python/build_management/build_manager.py#L271) выбирается фаззер (fuzz target) для запуска (подробнее [здесь](https://hackmd.io/@reverse-clusterfuzz/HktT2JF8U)) и устанавливается переменная среды `FUZZ_TARGET`. ## Фаззинг После обновления всех копонентов выполняется фаззинг. Для libFuzzer он реализуется функцией [`do_engine_fuzzing`](https://github.com/google/clusterfuzz/blob/master/src/python/bot/tasks/fuzz_task.py#L1575), поскольку libFuzzer регистрируется при старте в `_ENGINES` ```python= def run(): """Initialise builtin fuzzing engines.""" engine.register('libFuzzer', libFuzzer_engine.LibFuzzerEngine) engine.register('honggfuzz', honggfuzz_engine.HonggfuzzEngine) engine.register('syzkaller', syzkaller_engine.SyzkallerEngine) ``` Сначала происходит скачивание *корпусов* (corpus) из GCS. Корпуса будут использоваться мутатором для генерации входных данных (fuzz input) ```python= # Synchronize corpus files with GCS sync_corpus_directory = builtin.get_corpus_directory( self.data_directory, self.fuzz_target.project_qualified_name()) self.sync_corpus(sync_corpus_directory) ``` Потом происходит непосредственно процесс фаззинга со сбором крешей и статистики ```python= # Do the actual fuzzing. for fuzzing_round in range(environment.get_value('MAX_TESTCASES', 1)): logs.log('Fuzzing round {}.'.format(fuzzing_round)) result, current_fuzzer_metadata, fuzzing_strategies = run_engine_fuzzer( engine_impl, self.fuzz_target.binary, sync_corpus_directory, self.testcase_directory) fuzzer_metadata.update(current_fuzzer_metadata) # Prepare stats. testcase_run = engine_common.get_testcase_run(result.stats, result.command) ``` В функции [`run_engine_fuzzer`](https://github.com/google/clusterfuzz/blob/master/src/python/bot/tasks/fuzz_task.py#L1287). Есть две стадии: подготовка (`engine_impl.prepare`) и фаззинг (`engine_impl.fuzz`). На стадии подготовки выбираются стратегии для эффективного фаззинга, проверется наличие словарей, количество тест-кейсов в *корпусе* ([файл стратегий](https://github.com/google/clusterfuzz/blob/master/src/python/fuzzing/strategy.py)). На стадии фаззинга запускается фаззер, который может работать не более чем `max_time` секунд. То есть либо он отработает 1 тест-кейс, либо будет остановлен по истечении времени. Всё это реализуется классом [`LibFuzzerEgine`](https://github.com/google/clusterfuzz/blob/master/src/python/bot/fuzzers/libFuzzer/engine.py#L84). Для запуска и остановки фаззера используется модуль subprocess в функции [`ProcessRunner.run_and_wait`](https://github.com/google/clusterfuzz/blob/master/src/python/system/new_process.py#L301) После завершения работы фаззера парсится его вывод, собираются необходимые характеристики. Всё это происходит тесткейс за тесткейсом. Когда все тесткейсы отработаны, раунд завершается. Настройки фаззеров - сколько тесткейсов по умолчанию, количество потоков, задержки - находятся в [`setup.py`](https://github.com/google/clusterfuzz/blob/master/src/local/butler/scripts/setup.py)