diff --git a/README.md b/README.md index 5c28d29..86f2417 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ FUTAG — это автоматизированный инструмент генерации фаззинг-целей для программных библиотек. В отличие от обычных программ, программная библиотека может не содержать точки входа и не принимать входные данные, поэтому создание вручную фаззинг-цели для анализа программных библиотек остается проблемой и требует ресурсов. Одним из решением данной проблемы является автоматизация процесса создания фаззинг-целей, что уменьшает количество затрачиваемых ресурсов. FUTAG использует инструменты Clang и Clang LLVM в качестве внешнего интерфейса для анализа библиотек и генерации фаззинг-целей. -FUTAG во время работы использует статический анализ для поиска: +FUTAG запускает статический анализ во время сборки библиотеки для поиска: - Зависимостей сущностей (типы данных, функции, структуры и т.д.) в исходном коде целевой библиотеки. - Контекста использования библиотеки. Далее информация, полученная по результатам статического анализа, используется для генерации фаззинг-целей. @@ -66,12 +66,17 @@ FUTAG во время работы использует статический # предварительно должен быть установлен пакет futag-<версия>.tar.gz from futag.preprocessor import * -testing_lib = Builder( - "futag-llvm/", # путь к директории "futag-llvm" [2.2.] - "path/to/library/source/code" # путь к директории содержащей исходные кода исследуемого ПО +FUTAG_PATH = "/home/futag/Futag-tests/futag-llvm/" +lib_path = "path/to/library/source/code" +build_test = Builder( + FUTAG_PATH, + lib_path, + clean=True, # удалить все папки сгенерированные Futag-ом перед сборкой + # processes=4, # количество задач при сборке + # build_ex_params="--with-openssl --with-mhash" # дополнительные параметры при сборке библиотеки ) -testing_lib.auto_build() -testing_lib.analyze() +build_test.auto_build() +build_test.analyze() ``` - Генерация и компиляция драйверов @@ -80,18 +85,23 @@ testing_lib.analyze() # предварительно должен быть установлен пакет futag-<версия>.tar.gz from futag.generator import * -g = Generator( - "futag-llvm/", # путь к директории "futag-llvm" - "path/to/library/source/code" # путь к директории содержащей исходные кода исследуемого ПО +FUTAG_PATH = "/home/futag/Futag-tests/futag-llvm/" +lib_path = "path/to/library/source/code" + +generator = Generator( + FUTAG_PATH, # путь к директории "futag-llvm" + lib_path # путь к директории содержащей исходные кода исследуемого ПО ) # Генерация фаззинг-оберток -g.gen_targets( +generator.gen_targets( anonymous=False # опция для генерации фаззинг-обертки для функций, которые не имеют публичный доступ ) - # Compile fuzz drivers -g.compile_targets() +generator.compile_targets( + 4, # количество задач при сборке + # extra_include="-DHAVE_CONFIG_H" # дополнительные параметры при сборке библиотеки +) ``` По-умолчанию, успешно скомпилированные фаззинг-обертки для целевых функций находятся в каталоге futag-fuzz-drivers, где для каждой целевой функции создаётся своя поддиректория название которой совпадает с именем целевой функции. Если для функции сгенерировалось несколько фаззинг-оберток, в подкаталоге целевой функции создаются соответствующие директории, где к имени целевой функции добавляется порядковый номер. diff --git a/src/Checkers/lib/FutagTest.cpp.txt b/src/Checkers/lib/FutagTest.cpp.txt new file mode 100644 index 0000000..a8d6ebd --- /dev/null +++ b/src/Checkers/lib/FutagTest.cpp.txt @@ -0,0 +1,485 @@ +//== FutagTest.cpp ----------------------------------- -*- C++ -*--=// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +#include "clang/Tooling/Tooling.h" + +#include +#include +#include +#include +#include +#include +#include "Futag/Basic.h" + +using namespace clang; +using namespace ento; +using namespace std; +using namespace futag; +namespace +{ + + class FutagTest : public Checker> + { + public: + bool ChkInPrototype = false; + bool ChkArgNames = false; + string ArgNamesList = ""; + bool ChkFuncCalls = false; + string FuncCallsList = ""; + void checkASTDecl(const FunctionDecl *D, AnalysisManager &Mgr, + BugReporter &BR) const; + }; + +} // namespace + +void FutagTest::checkASTDecl(const FunctionDecl *func, AnalysisManager &Mgr, BugReporter &bugReporter) const +{ + + if (Mgr.getSourceManager().isInSystemHeader(func->getBeginLoc())) + { + return; + } + if (!func->hasPrototype() || !func->hasBody() || func->parameters().size() < 1) + { + return; + } + + FullSourceLoc fLoc = Mgr.getASTContext().getFullLoc(func->getBeginLoc()); + if (!fLoc.getFileEntry()) + { + return; + } + + llvm::outs() << " function name: " << func->getQualifiedNameAsString() << "\n"; + // for (ParmVarDecl *x : func->parameters()) + for (uint32_t paramIdx = 0; paramIdx < func->getNumParams(); ++paramIdx) + { + + auto currParam = func->parameters()[paramIdx]; + const Type *currType = dyn_cast(currParam->getType()); + auto curr = currParam->getType(); + llvm::outs() << "!!! Analyze parameter " << currParam->getNameAsString() << " of type: " << curr.getAsString() << "\n"; + if (!futag::isSimpleType(curr)){ + llvm::outs() << "!!! parameter " << currParam->getNameAsString() << " of type: " << curr.getAsString() << " not simple!!\n"; + continue; + } + vector gen_field_list = futag::getGenField(curr); + for (auto g : gen_field_list) + { + llvm::outs() << " -- g.curr_type_name: " << g.curr_type_name << "\n"; + llvm::outs() << " -- g.base_type_name: " << g.base_type_name << "\n"; + llvm::outs() << " -- g.length: " << g.length << "\n"; + llvm::outs() << " -- g.local_qualifier: " << g.local_qualifier << "\n"; + llvm::outs() << " -- g.gen_type: " << futag::GetFutagGenTypeFromIdx(g.gen_type) << "\n"; + llvm::outs() << " -- -- -- -- -- -- \n"; + } + + // llvm::outs() << "\n-----Check array: \n"; + + // QualType PType = func->parameters()[paramIdx]->getOriginalType(); + // if (const auto *AT = + // dyn_cast(PType->getCanonicalTypeInternal())) + // { + // llvm::outs() << "func->parameters()[paramIdx]->getOriginalType(): " << PType.getAsString() << " \n"; + // llvm::outs() << "PType->getCanonicalTypeInternal(): " << PType->getCanonicalTypeInternal().getAsString() << " \n"; + // // Use array's original type only if it has known number of + // // elements. + // llvm::outs() << " -- element type: " << AT->getElementType().getAsString() << "\n"; + // if (const auto *CAT = dyn_cast(AT)) + // { + // llvm::outs() << "-- size: " << llvm::utostr(CAT->getSize().getZExtValue()) << "\n"; + // } + // else + // { + // llvm::outs() << " -- unknown size!!! \n"; + // } + + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is a dyn_cast with getCanonicalTypeInternal \n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not a dyn_cast with getCanonicalTypeInternal \n"; + // } + + // const ArrayType *ArrayTy = + // Mgr.getASTContext().getAsArrayType(currParam->getType()); + // if (ArrayTy) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is a getAsConstantArrayType \n"; + // llvm::outs() << " -- elementype: " << currParam->getType()->getAsArrayTypeUnsafe()->getElementType().getAsString() << "\n"; + // // llvm::outs() << " -- size: " << to_string(ArrayTy->getSize().getSExtValue()) << "\n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not getAsConstantArrayType \n"; + // } + // auto t = dyn_cast(currParam->getType()); + // if (t) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is a dyn_cast constant array type \n"; + // llvm::outs() << " -- elementype: " << currParam->getType()->getAsArrayTypeUnsafe()->getElementType().getAsString() << "\n"; + // // llvm::outs() << " -- size: " << to_string(t->getSize().getSExtValue()) << "\n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not a dyn_cast constant array type \n"; + // } + + // if (curr->isConstantArrayType()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is a constant array type \n"; + // auto t = dyn_cast(currParam->getType()); + // if (t) + // { + // llvm::outs() << " -- elementype: " << currParam->getType()->getAsArrayTypeUnsafe()->getElementType().getAsString() << "\n"; + // llvm::outs() << " -- size: " << to_string(t->getSize().getSExtValue()) << "\n"; + // } + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not a constant array type \n"; + // } + // if (curr->isArrayType()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is an array type \n"; + // auto t = dyn_cast(currParam->getType()); + // if (t) + // { + // llvm::outs() << " -- elementype: " << currParam->getType()->getAsArrayTypeUnsafe()->getElementType().getAsString() << "\n"; + // llvm::outs() << " -- size: " << to_string(t->getSize().getSExtValue()) << "\n"; + // } + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not an array type \n"; + // } + // if (curr->isVariableArrayType()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is a variable array type \n"; + // auto t = dyn_cast(currParam->getType()); + // if (t) + // { + // llvm::outs() << " -- elementype: " << currParam->getType()->getAsArrayTypeUnsafe()->getElementType().getAsString() << "\n"; + // llvm::outs() << " -- size: " << to_string(t->getSize().getSExtValue()) << "\n"; + // } + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not a variable array type \n"; + // } + // if (curr->isDependentSizedArrayType()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is Dependent Sized Array Type\n"; + // auto t = dyn_cast(currParam->getType()); + // if (t) + // { + // llvm::outs() << " -- elementype: " << currParam->getType()->getAsArrayTypeUnsafe()->getElementType().getAsString() << "\n"; + // llvm::outs() << " -- size: " << to_string(t->getSize().getSExtValue()) << "\n"; + // } + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not Dependent SizedArrayType\n"; + // } + // llvm::outs() << "end of Check array! \n"; + // if (futag::isSimpleType(currParam->getType())) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is simple \n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not simple \n"; + // } + // // const Type *currType = dyn_cast(currParam->getType()); + // if (currType->isEnumeralType()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is an EnumeralType \n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not an EnumeralType \n"; + // } + // if (curr->isEnumeralType()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is an EnumeralType \n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not an EnumeralType \n"; + // } + // llvm::outs() << "\n"; + + // while (curr->isPointerType()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString(); + // curr = curr->getPointeeType(); + // llvm::outs() << " has pointee type: " << curr.getAsString() << " \n"; + // if (curr.hasLocalQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has local Qualifier!\n"; + // llvm::outs() << " -- local qualifier: " << curr.getLocalQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have local Qualifier!\n"; + // } + + // if (curr.hasQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has Qualifier!\n"; + // llvm::outs() << " -- qualifier: " << curr.getQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have Qualifier!\n"; + // } + // if (futag::isSimpleType(curr)) + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is simple \n"; + // } + // else + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is not simple \n"; + // } + // } + // llvm::outs() << "\n"; + // if (curr->isIncompleteType()) + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is an incomplete type \n"; + // } + // else + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is not an incomplete type \n"; + // } + // if (curr->isRecordType()) + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is a record type \n"; + // } + // else + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is not an incomplete type \n"; + // } + + // llvm::outs() << "\n"; + // llvm::outs() << " -- getTypeClassName: " << curr->getTypeClassName() << "\n"; + // llvm::outs() << "\n"; + // llvm::outs() << "\n"; + + // llvm::outs() << "getGenField:::::\n"; + + // if (currParam->getType()->getTypeClassName() == "Typedef") + // { + // if (currParam->getType().isCanonical()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is canonical, canonical type: " << currParam->getType().getCanonicalType().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not canonical\n"; + // } + // } + // else + // { + // llvm::outs() << " -- typeclassname: " << currParam->getType()->getTypeClassName() << "\n"; + // } + + // if (!currParam->getType()->isBuiltinType()) + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not builtin type \n"; + // } + // else + // { + // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is builtin type \n"; + // } + // auto curr = currParam->getType(); + // while (curr->isPointerType()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString(); + // curr = curr->getPointeeType(); + // llvm::outs() << " has pointee type: " << curr.getAsString() << " \n"; + // if (curr.hasLocalQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has local Qualifier!\n"; + // llvm::outs() << " -- local qualifier: " << curr.getLocalQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have local Qualifier!\n"; + // } + + // if (curr.hasQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has Qualifier!\n"; + // llvm::outs() << " -- qualifier: " << curr.getQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have Qualifier!\n"; + // } + // if (futag::isSimpleType(curr)) + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is simple \n"; + // } + // else + // { + // llvm::outs() << " -- type " << curr.getAsString() << " is not simple \n"; + // } + // } + + // // if (currParam->getType().isCanonical()) + // // { + // // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is canonical, canonical type: " << currParam->getType().getCanonicalType().getAsString() << "\n"; + // // } + // // else + // // { + // // llvm::outs() << " -- type " << currParam->getType().getAsString() << " is not canonical\n"; + // // } + // if (paramIdx > 0) + // { + // QualType curr = currParam->getType(); + // auto prevParam = func->parameters()[paramIdx - 1]; + // QualType prev = prevParam->getType(); + + // if (prev.isCanonical()) + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " is canonical, canonical type: " << prev.getCanonicalType().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " is not canonical\n"; + // } + + // if (prev.hasLocalQualifiers()) + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " has local Qualifier!\n"; + // llvm::outs() << " -- local qualifier: " << prev.getLocalQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " does not have local Qualifier!\n"; + // } + + // if (prev.hasQualifiers()) + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " has Qualifier!\n"; + // llvm::outs() << " -- qualifier: " << prev.getQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " does not have Qualifier!\n"; + // } + // llvm::outs() << "\n"; + + // if (curr.isCanonical()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " is canonical, canonical type: " << curr.getCanonicalType().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " is not canonical\n"; + // } + + // if (curr.hasLocalQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has local Qualifier!\n"; + // llvm::outs() << " -- local qualifier: " << curr.getLocalQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have local Qualifier!\n"; + // } + + // if (curr.hasQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has Qualifier!\n"; + // llvm::outs() << " -- qualifier: " << curr.getQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have Qualifier!\n"; + // } + + // llvm::outs() << "\n"; + + // while (prev->isPointerType()) + // { + // llvm::outs() << " -- type prev " << prev.getAsString(); + // prev = prev->getPointeeType(); + // llvm::outs() << " has pointee type: " << prev.getAsString() << " \n"; + // if (prev.hasLocalQualifiers()) + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " has local Qualifier!\n"; + // llvm::outs() << " -- local qualifier: " << prev.getLocalQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " does not have local Qualifier!\n"; + // } + + // if (prev.hasQualifiers()) + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " has Qualifier!\n"; + // llvm::outs() << " -- qualifier: " << prev.getQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type prev " << prev.getAsString() << " does not have Qualifier!\n"; + // } + // } + + // llvm::outs() << "\n"; + + // while (curr->isPointerType()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString(); + // curr = curr->getPointeeType(); + // llvm::outs() << " has pointee type: " << curr.getAsString() << " \n"; + // if (curr.hasLocalQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has local Qualifier!\n"; + // llvm::outs() << " -- local qualifier: " << curr.getLocalQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have local Qualifier!\n"; + // } + + // if (curr.hasQualifiers()) + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " has Qualifier!\n"; + // llvm::outs() << " -- qualifier: " << curr.getQualifiers().getAsString() << "\n"; + // } + // else + // { + // llvm::outs() << " -- type curr " << curr.getAsString() << " does not have Qualifier!\n"; + // } + // } + // // if (currParam->getType() == prevParam->getType()){ + // // llvm::outs() << " -- !!!! URraaa \n"; + // // } + // // llvm::outs() << "-- currtype: " << curr.getAsString() << "\n"; + // // llvm::outs() << "-- prevtype: " << prev.getAsString() << "\n"; + // if (prev == curr) + // { + // llvm::outs() << " -- !!!! URraaa \n"; + // } + // } + } + return; +} + +void ento::registerFutagTest(CheckerManager &Mgr) +{ + auto *Chk = Mgr.registerChecker(); +} + +bool ento::shouldRegisterFutagTest(const CheckerManager &mgr) +{ + return true; +} \ No newline at end of file diff --git a/src/python/futag-package/dist/futag-1.2.1-py3-none-any.whl b/src/python/futag-package/dist/futag-1.2.1-py3-none-any.whl index b90e127..30ca656 100644 Binary files a/src/python/futag-package/dist/futag-1.2.1-py3-none-any.whl and b/src/python/futag-package/dist/futag-1.2.1-py3-none-any.whl differ diff --git a/src/python/futag-package/dist/futag-1.2.1.tar.gz b/src/python/futag-package/dist/futag-1.2.1.tar.gz index f6cb006..cb183f4 100644 Binary files a/src/python/futag-package/dist/futag-1.2.1.tar.gz and b/src/python/futag-package/dist/futag-1.2.1.tar.gz differ diff --git a/src/python/futag-package/src/futag.egg-info/PKG-INFO b/src/python/futag-package/src/futag.egg-info/PKG-INFO index bc83523..8d81177 100644 --- a/src/python/futag-package/src/futag.egg-info/PKG-INFO +++ b/src/python/futag-package/src/futag.egg-info/PKG-INFO @@ -7,7 +7,6 @@ Author: Futag-team of ISP RAS Author-email: thientc84@gmail.com License: LICENSE Project-URL: Bug Tracker, https://github.com/ispras/Futag/issues -Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: GNU Classifier: Operating System :: OS Independent @@ -232,4 +231,3 @@ class Fuzzer(builtins.object) | | ---------------------------------------------------------------------- ``` - diff --git a/src/python/template-script.py b/src/python/template-script.py index 46f2df6..cb77ad4 100644 --- a/src/python/template-script.py +++ b/src/python/template-script.py @@ -2,7 +2,7 @@ from futag.preprocessor import * from futag.generator import * -lib_test = Builder( +test_build = Builder( "../futag-llvm", #Путь к рабочей директории futag "../json-c", #Путь к директории исходных текстов исследуемого приложения "-g -O0", #Флаги при сборке @@ -14,14 +14,14 @@ "--disable-zip" #Дополнительные параметры компилятора (Необязательный параметр) ) -lib_test.auto_build() -lib_test.analyze() +test_build.auto_build() +test_build.analyze() -lib_test = Generator( +generator = Generator( "../futag-llvm/", "json-c", ) -lib_test.gen_targets() -lib_test.compile_targets(True, 4) +generator.gen_targets() +generator.compile_targets(True, 4) print("-- [Futag]: fuzz-drivers are saved in json-c/futag-fuzz-targets!")