
Распределённый фаззинг-движок с управлением покрытием, совместимый с целями libFuzzer; масштабируется до тысяч параллельных задач, использует санитайзеры и дистилляцию корпуса для обнаружения ошибок.
А почему бы и нет? Мы сейчас пытаемся фаззить очень большие и очень медленные цели, для которых libFuzzer, AFL и подобные не всегда хорошо масштабируются. Один из мотивирующих примеров — SiliFuzz. Работая над Centipede, мы планируем экспериментировать с новыми подходами к массовому дифференциальному фаззингу, которые существующие движки фаззинга не пытаются реализовать.
Примечательные особенности:
Поддержка fuzz-целей на основе libFuzzer «из коробки». Чтобы использовать вашу любимую функцию LLVMFuzzerTestOneInput(), вам нужно лишь собрать цель с опциями компилятора и компоновщика Centipede.
В разработке. Мы тестируем Centipede внутри небольшой команды на паре целей. Если вы не участник проекта Centipede и не хотите нам помочь, вам, вероятно, пока не стоит читать дальше.
Масштабируемость. Предполагается возможность запускать любое количество параллельных заданий с очень небольшими накладными расходами на взаимодействие. Сейчас мы тестируем 100 локальных заданий и 10 тысяч заданий на кластере.
Внешний процесс. Цель выполняется в отдельном процессе. Любые сбои в ней не повлияют на фаззер. Centipede также можно использовать внутри процесса, но этот режим не является основной целью. Если ваша цель небольшая и быстрая, вам, вероятно, по-прежнему стоит использовать libFuzzer.
Интеграция с санитайзерами достигается с помощью отдельных сборок. Если во время фаззинга вы хотите находить ошибки с помощью ASAN, MSAN или TSAN, вам потребуется предоставить отдельные бинарные файлы для каждого санитайзера, а также один основной бинарный файл для самого Centipede. Основной бинарный файл не должен использовать ни один из санитайзеров.
Никакая часть внутреннего интерфейса не стабильна. На этом этапе может измениться что угодно.
Программа, которая генерирует бесконечный поток входных данных для цели и управляет выполнением.
Бинарный файл, библиотека, API или вообще что угодно, что может принимать байты на вход и выдавать какие-либо данные о покрытии на выходе. Цель libFuzzer может быть целью Centipede. Подробнее читайте здесь.
Последовательность байтов, которую можно подать цели. Входные данные могут быть произвольным набором байтов или структурированными данными, например сериализованным прото.
Число, представляющее некоторое уникальное поведение цели. Например, признак 1234567 может означать, что базовый блок номер 987 в цели был выполнен 7 раз. При выполнении входных данных с целью фаззер собирает признаки, наблюдавшиеся во время выполнения.
Набор признаков, связанный с одним конкретным входным набором данных.
Некоторая информация о поведении цели при выполнении заданных входных данных. Покрытие обычно представляется как набор признаков, которые входные данные вызвали в цели.
Функция, которая принимает байты на вход и выдаёт небольшую случайную мутацию входных данных. См. также: структурно-зависимый фаззинг.
Функция, которая умеет подавать входные данные цели и получать взамен покрытие (то есть выполнять).
Настраиваемый движок фаззинга, который позволяет пользователю заменять мутатор и исполнитель.
Библиотека, реализующая интерфейс исполнителя, ожидаемый фаззером Centipede. Runner умеет запускать цель, инструментированную sancov, собирать результирующее покрытие и передавать его обратно в Centipede. Потенциальные fuzz-цели Centipede могут быть слинкованы с этой библиотекой, чтобы их можно было запускать через Centipede.
Набор входных данных.
Процесс выбора подмножества большего корпуса такого, что подмножество имеет те же признаки покрытия, что и исходный корпус.
Файл, представляющий подмножество корпуса, и другой файл, представляющий наборы признаков для того же подмножества корпуса.
Слить шард B в шард A означает: для каждого входного набора данных в шарде B, признаки которого отсутствуют в шарде A, добавить этот входной набор данных в A.
Один процесс фаззера. Одно задание записывает только в один шард, но может читать несколько шардов.
Локальная или удалённая директория, содержащая данные, создаваемые или потребляемые фаззером.
git clone https://github.com/google/centipede.git
cd centipede
CENTIPEDE_SRC=`pwd`
BIN_DIR=$CENTIPEDE_SRC/bazel-bin
bazel build -c opt :all
Что понадобится для последующих шагов:
$BIN_DIR/centipede — бинарный файл движка (фаззера).$BIN_DIR/libcentipede_runner.pic.a — библиотека, которую нужно слинковать с вашей fuzz-целью (runner).$CENTIPEDE_SRC/clang-flags.txt — рекомендуемые флаги компиляции clang для цели.Вы можете оставить эти файлы на месте или скопировать куда-нибудь.
Мы приводим два примера сборки цели: один крошечный однострочный файл и libpng. После сборки цели переходите к шагу запуска fuzz-цели.
В этом примере используется одна из простых примерных fuzz-целей, также известных как puzzles (головоломки), включённых в репозиторий Centipede.
ПРИМЕЧАНИЕ. В командах ниже используются флаги из $CENTIPEDE_SRC/clang-flags.txt. Вы можете выбрать другой набор флагов инструментирования: clang-flags.txt предоставляет лишь простой вариант по умолчанию.
FUZZ_TARGET=byte_cmp_4 # или любой другой исходник из $CENTIPEDE_SRC/puzzles
clang++ @$CENTIPEDE_SRC/clang-flags.txt -c $CENTIPEDE_SRC/puzzles/$FUZZ_TARGET.cc -o $BIN_DIR/$FUZZ_TARGET.o
На этом шаге только что собранная fuzz-цель связывается с libcentipede_runner.pic.a и другими необходимыми библиотеками.
clang++ $BIN_DIR/$FUZZ_TARGET.o $BIN_DIR/libcentipede_runner.pic.a \
-ldl -lrt -lpthread -o $BIN_DIR/$FUZZ_TARGET
Переходите к шагу запуска.
LIBPNG_BRANCH=v1.6.37 # Вы можете поэкспериментировать с другими ветками, если хотите
git clone --branch $LIBPNG_BRANCH --single-branch https://github.com/glennrp/libpng.git
cd libpng
CC=clang CFLAGS=@$CENTIPEDE_SRC/clang-flags.txt ./configure --disable-shared
make -j
FUZZ_TARGET=libpng_read_fuzzer
clang++ -include cstdlib \
./contrib/oss-fuzz/$FUZZ_TARGET.cc \
./.libs/libpng16.a \
$BIN_DIR/libcentipede_runner.pic.a \
-ldl -lrt -lpthread -lz \
-o $BIN_DIR/$FUZZ_TARGET
Локальный запуск не даст полного масштаба, но может быть полезен на этапе разработки фаззера. Мы рекомендуем скопировать и фаззер, и цель в локальную директорию перед запуском, чтобы не нагружать сетевую файловую систему.
WD=$HOME/centipede_run
mkdir -p $WD