diff options
| author | Pimyn Girgis <bemenboshra2001@gmail.com> | 2024-09-04 10:22:56 +0000 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2024-09-09 13:14:54 +0000 |
| commit | 37f6c627c0e515d3c1bc57da1e15ddf208f5a23b (patch) | |
| tree | f4451d64dd6baeaf33bb9af726b3e9e41739a556 /tools | |
| parent | 073f8be214232113bbf75d16a9bb0372beee85b9 (diff) | |
tools/syz-declextract: restructuring for clang tool
Split the Matcher into two classes for system calls and netlinks. Made the system call extraction more robust by
avoiding using constants and extracting their values instead.
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/syz-declextract/syz-declextract.cpp | 142 |
1 files changed, 78 insertions, 64 deletions
diff --git a/tools/syz-declextract/syz-declextract.cpp b/tools/syz-declextract/syz-declextract.cpp index 66ce053a9..60506f79a 100644 --- a/tools/syz-declextract/syz-declextract.cpp +++ b/tools/syz-declextract/syz-declextract.cpp @@ -68,7 +68,63 @@ public: } }; -class Matcher : public MatchFinder::MatchCallback { +class SyscallMatcher : public MatchFinder::MatchCallback { +private: + const std::string getSyzType(const std::string &type) { return "intptr"; } + const std::string swapIfReservedKeyword(const std::string &word) { + if (word == "resource") + return "rsrc"; + return word; + } + unsigned int nameIndex{0}, argcIndex{0}, typesIndex{0}, argsIndex{0}; + bool isInitialized{false}; + llvm::ArrayRef<Expr *> getVarDeclInitList(Expr *init, const ASTContext *context) { + return llvm::dyn_cast<InitListExpr>( + llvm::dyn_cast<VarDecl>(init->getAsBuiltinConstantDeclRef(*context)->getUnderlyingDecl())->getInit()) + ->inits(); + } + + std::vector<Param> getArgs(Expr *types, Expr *names, int argc, ASTContext *context) { + std::vector<Param> args(argc); + if (argc) { + int i = 0; + for (const auto *type : getVarDeclInitList(types, context)) { // get parameter types. + args[i++].type = std::move(*type->tryEvaluateString(*context)); + } + + i = 0; + for (const auto *name : getVarDeclInitList(names, context)) { // get parameter names + args[i++].name = std::move(*name->tryEvaluateString(*context)); + } + } + return args; + } + +public: + void virtual run(const MatchFinder::MatchResult &Result) override { + ASTContext *context = Result.Context; + const auto *initList = Result.Nodes.getNodeAs<InitListExpr>("initList"); + if (!isInitialized) { + argcIndex = Result.Nodes.getNodeAs<FieldDecl>("nb_args")->getFieldIndex(); + typesIndex = Result.Nodes.getNodeAs<FieldDecl>("types")->getFieldIndex(); + argsIndex = Result.Nodes.getNodeAs<FieldDecl>("args")->getFieldIndex(); + nameIndex = Result.Nodes.getNodeAs<FieldDecl>("name")->getFieldIndex(); + } + // values contains the initializer list for the struct `syscall_metadata` + auto values = initList->inits(); + int argc = values[argcIndex]->getIntegerConstantExpr(*context)->getSExtValue(); + + printf("%s$auto(", values[nameIndex]->tryEvaluateString(*context)->c_str() + 4); // name + const char *sep = ""; + for (const auto &arg : getArgs(values[typesIndex], values[argsIndex], argc, context)) { + printf("%s%s %s", sep, swapIfReservedKeyword(arg.name).c_str(), getSyzType(arg.type).c_str()); + sep = ", "; + } + puts(") (automatic)"); + } +}; + +class NetlinkPolicyMatcher : public MatchFinder::MatchCallback { private: const std::string nlaToSyz(const Expr *const policyType) { // NOTE:This check is for when the policy is missing the field `type`. @@ -114,59 +170,9 @@ private: fprintf(stderr, "Unsupported netlink type %s\n", type.c_str()); exit(1); } - const std::string getSyzType(const std::string &type) { return "intptr"; } - const std::string swapIfReservedKeyword(const std::string &word) { - if (word == "resource") - return "rsrc"; - return word; - } - - void syscall(const MatchFinder::MatchResult &Result) { - ASTContext *context = Result.Context; - const auto *varDecl = Result.Nodes.getNodeAs<VarDecl>("syscall"); - if (!varDecl || !varDecl->getInit()) - return; - - // values contains the initializer list for the struct `syscall_metadata` - auto values = llvm::dyn_cast<InitListExpr>(varDecl->getInit())->inits(); - if (values.empty()) - return; - - int argc = *values[2]->getIntegerConstantExpr(*context)->getRawData(); - - std::vector<Param> args(argc); - if (argc) { - int i = 0; - for (const auto *type : // get parameter types - llvm::dyn_cast<InitListExpr>( - llvm::dyn_cast<VarDecl>(values[3]->getAsBuiltinConstantDeclRef(*context)->getUnderlyingDecl()) - ->getInit()) - ->inits()) { - args[i++].type = std::move(*type->tryEvaluateString(*context)); - } - - i = 0; - for (const auto *name : // get parameter names - llvm::dyn_cast<InitListExpr>( - llvm::dyn_cast<VarDecl>(values[4]->getAsBuiltinConstantDeclRef(*context)->getUnderlyingDecl()) - ->getInit()) - ->inits()) { - args[i++].name = std::move(*name->tryEvaluateString(*context)); - } - } - - printf("%s$auto(", values[0]->tryEvaluateString(*context)->c_str() + 4); // name - const char *sep = ""; - for (const auto &arg : args) { - printf("%s%s %s", sep, swapIfReservedKeyword(arg.name).c_str(), getSyzType(arg.type).c_str()); - sep = ", "; - } - puts(") (automatic)"); - } void netlink(const MatchFinder::MatchResult &Result) { ASTContext *context = Result.Context; - std::string output; const auto *netlinkDecl = Result.Nodes.getNodeAs<VarDecl>("netlink"); if (!netlinkDecl) { return; @@ -279,17 +285,16 @@ private: void genlFamily(const MatchFinder::MatchResult &Result) { ASTContext *context = Result.Context; - const auto *genlFamily = Result.Nodes.getNodeAs<RecordDecl>("genl_family"); - if (!genlFamily) { - return; - } - for (const auto &field : genlFamily->fields()) { - genlFamilyMember[field->getNameAsString()] = field->getFieldIndex(); - } const auto *genlFamilyInit = Result.Nodes.getNodeAs<InitListExpr>("genl_family_init"); if (!genlFamilyInit) { return; } + if (genlFamilyMember.empty()) { + const auto *genlFamily = Result.Nodes.getNodeAs<RecordDecl>("genl_family"); + for (const auto &field : genlFamily->fields()) { + genlFamilyMember[field->getNameAsString()] = field->getFieldIndex(); + } + } auto name = llvm::dyn_cast<StringLiteral>(genlFamilyInit->getInit(genlFamilyMember["name"]))->getString().str(); std::replace(name.begin(), name.end(), '.', '_'); // Illegal character. @@ -332,7 +337,6 @@ private: public: virtual void run(const MatchFinder::MatchResult &Result) override { - syscall(Result); netlink(Result); genlFamily(Result); }; @@ -350,22 +354,32 @@ int main(int argc, const char **argv) { clang::tooling::CommonOptionsParser &OptionsParser = ExpectedParser.get(); clang::tooling::ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); - Matcher Printer; + NetlinkPolicyMatcher NetlinkPolicyMatcher; + SyscallMatcher SyscallMatcher; MatchFinder Finder; + Finder.addMatcher( - varDecl(isExpandedFromMacro("SYSCALL_METADATA"), hasType(recordDecl(hasName("syscall_metadata"))), isDefinition()) + varDecl( + isExpandedFromMacro("SYSCALL_METADATA"), + hasType(recordDecl(hasName("syscall_metadata"), has(fieldDecl(hasName("nb_args")).bind("nb_args")), + has(fieldDecl(hasName("types")).bind("types")), + has(fieldDecl(hasName("name")).bind("name")), has(fieldDecl(hasName("args")).bind("args"))) + .bind("syscall_metadata")), + has(initListExpr().bind("initList"))) .bind("syscall"), - &Printer); + &SyscallMatcher); + Finder.addMatcher(varDecl(hasType(constantArrayType(hasElementType(hasDeclaration( recordDecl(hasName("nla_policy")).bind("nla_policy")))) .bind("nla_policy_array")), isDefinition()) .bind("netlink"), - &Printer); + &NetlinkPolicyMatcher); + Finder.addMatcher(varDecl(hasType(recordDecl(hasName("genl_family")).bind("genl_family")), has(initListExpr().bind("genl_family_init"))) .bind("genl_family_decl"), - &Printer); + &NetlinkPolicyMatcher); return Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get()); } |
