Для создания фаззинг-оберток для функций в библиотеке, Futag запускает статический анализ во время компиляции данной библиотеки. Этот процесс выполняется Futag автоматически и состоит из следующих шагов:
- в каталоге исходного кода библиотеки создается папка futag-build
- осуществляется переход в папку futag-build
- в папке futag-build запускается configure или cmake с заданными аргументами (install_path, build_ex_params, и т.д.)
- запускается make (в сфере scan-build с чекером futag.FutagFunctionAnalyzer), зависимости извлекаются и сохраняются в папку analysis_path
- выполняется удаление собранных файлов
- запускается make с параметрами flags. По умолчанию параметры имеют значение: "-fsanitize=address -g -O0 -fprofile-instr-generate -fcoverage-mapping" - (AddressSanitizer, debug, without optimization, information generation for coverage) - в результате сборки с параметрами по умолчанию формируется фаззинг-цель, включающая опции сбора отладочной информации и покрытия.
- запустить make install чтобы установить библиотеку в пользовательскую папку.
Есть возможность объединить шаги [4] и [6], но scan-build не собирает с флагами "-fprofile-instr-generate -fcoverage-mapping", соответственно в собранной цели будет отсутстовать инструментация, позволяющая собирать информацию о покрытии.
Полную документацию python-модуля в составе Futag можно посмотреть по ссылке.
Класс Builder принимает следующие параметры:
class Builder:
"""Futag Builder Class"""
def __init__(self, futag_llvm_package: str, library_root: str, flags: str = COMPILER_FLAGS, clean: bool = False, build_path: str = BUILD_PATH, install_path: str = INSTALL_PATH, analysis_path: str = ANALYSIS_PATH, processes: int =4, build_ex_params=BUILD_EX_PARAMS):
"""
Parameters
----------
futag_llvm_package: str
(*required) path to the futag llvm package (with binaries, scripts, etc)
library_root: str
(*required) path to the library root
flags: str
flags for compiling. Default to "-fsanitize=address -g -O0 -fprofile-instr-generate -fcoverage-mapping"
clean: bool
Option for deleting futag folders if they are exist, default to False (futag-build, futag-install, futag-analysis).
build_path: str
path to the build directory, default to "futag-build". Be careful, this directory will be deleted and create again if clean set to True.
install_path: str
path to the install directory, default to "futag-install". Be careful, this directory will be deleted and create again if clean set to True.
analysis_path: str
path for saving report of analysis, default to "futag-analysis". Be careful, this directory will be deleted and create again if clean set to True.
processes: int
number of processes while building, default to 4.
build_ex_params: str
extra params for building, for example "--with-openssl" for building curl
"""
Примерный скрипт сборки библиотеки:
# package futag must be already installed
from futag.preprocessor import *
lib_test = Builder(
"Futag/futag-llvm/", # path to the futag-llvm
"path/to/library/source/code" # library root
)
lib_test.auto_build()
lib_test.analyze()
path/to/library/source/code можно задавать как ".", "~/", и т.д.
Если вы хотите скомпилировать библиотеку со своим флагами, вы сможете задать их с помощью параметра flags.
lib_test = Builder(
"/path/to/futag-llvm/",
".",
flags="-g -O0",
)
Если вы повторно запускаете Futag в каталоге исходного кода библиотеки, задав параметр clean=True вы можете принудительно удалить сгенерированные ранее папки futag-build, futag-install и futag-analysis.
lib_test = Builder(
"/path/to/futag-llvm/",
".",
flags="-g -O0",
True,
)
Папку сборки, папку для сохранения результата анализа, папку установки так же можно задавать с помощью следующих параметров:
lib_test = Builder(
"/path/to/futag-llvm/",
".",
flags="-g -O0",
True,
build_path="other-build-folder",
install_path="other-install-folder",
analysis_path="other-analysis-folder",
)
Так же можно задавать количество потоков для сборки параметром processes:
lib_test = Builder(
"/path/to/futag-llvm/",
".",
flags="-g -O0",
clean=True,
processes=8
)
Параметр build_ex_params полезен в случае нужно добавить дополнительные параметры при сборке. Например, собрать curl с параметром --without-ssl или --with-ssl
lib_test = Builder(
"/path/to/futag-llvm/",
".",
flags="-g -O0",
clean=True,
build_ex_params="--without-ssl"
)
Как можно интегрировать Futag с библиотекой, собираемой способом, отличным от поддерживаемых на текущий момент
Кроме cmake и configure библиотеки могут быть собраны разными способами: ninja, mach, и т.д.. В этом случае также можно запустить сборку под контролем средства scan-build в составе анализатора Futag, этот процесс состоит из следующих шагов:
- Подготовить свою библиотеку (с configure и т.д.)
- Собрать библиотеку под средством scan-build с анализатором Futag
$ /path/to/futag-llvm/package/bin/scan-build -enable-checker futag.FutagFunctionAnalyzer -analyzer-config futag.FutagFunctionAnalyzer:report_dir=/path/to/analysis/folder <your-build-script>
- Если у вас ninja можно запустить как:
$ /path/to/futag-llvm/package/bin/scan-build -enable-checker futag.FutagFunctionAnalyzer -analyzer-config futag.FutagFunctionAnalyzer:report_dir=/path/to/analysis/folder ninja -j4
- Если у вас свой скрипт build-lib.sh можно запустить как:
$ /path/to/futag-llvm/package/bin/scan-build -enable-checker futag.FutagFunctionAnalyzer -analyzer-config futag.FutagFunctionAnalyzer:report_dir=/path/to/analysis/folder build-lib.sh
- Запустить анализатор:
# package futag must be already installed
from futag.preprocessor import *
testing_lib = Builder(
"Futag/futag-llvm/", #Путь к рабочей директории futag
"path/to/library/source/code", #Путь к директории исходных текстов исследуемого приложения
)
testing_lib.analyze()
- Запустить генератор:
from futag.generator import *
from futag.sysmsg import *
g = Generator(
"Futag/futag-llvm/", #Путь к рабочей директории futag
"path/to/library/source/code", #Путь к директории исходных текстов исследуемого приложения
target_type=AFLPLUSPLUS, # Формат оберток LIBFUZZER или AFLPLUSPLUS
json_file="/path/to/analysis/folder/futag-analysis-result.json" #Путь к файлу результата анализа
)
g.gen_targets() # генерация фаззинг-оберток
g.compile_targets( # компиляция фаззинг-оберток
True, # генерация Makefile
16) # количество потоков при компиляции