From 37f6c627c0e515d3c1bc57da1e15ddf208f5a23b Mon Sep 17 00:00:00 2001 From: Pimyn Girgis Date: Wed, 4 Sep 2024 10:22:56 +0000 Subject: 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. --- tools/syz-declextract/syz-declextract.cpp | 142 ++++++++++++++++-------------- 1 file changed, 78 insertions(+), 64 deletions(-) (limited to 'tools') 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 getVarDeclInitList(Expr *init, const ASTContext *context) { + return llvm::dyn_cast( + llvm::dyn_cast(init->getAsBuiltinConstantDeclRef(*context)->getUnderlyingDecl())->getInit()) + ->inits(); + } + + std::vector getArgs(Expr *types, Expr *names, int argc, ASTContext *context) { + std::vector 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("initList"); + if (!isInitialized) { + argcIndex = Result.Nodes.getNodeAs("nb_args")->getFieldIndex(); + typesIndex = Result.Nodes.getNodeAs("types")->getFieldIndex(); + argsIndex = Result.Nodes.getNodeAs("args")->getFieldIndex(); + nameIndex = Result.Nodes.getNodeAs("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("syscall"); - if (!varDecl || !varDecl->getInit()) - return; - - // values contains the initializer list for the struct `syscall_metadata` - auto values = llvm::dyn_cast(varDecl->getInit())->inits(); - if (values.empty()) - return; - - int argc = *values[2]->getIntegerConstantExpr(*context)->getRawData(); - - std::vector args(argc); - if (argc) { - int i = 0; - for (const auto *type : // get parameter types - llvm::dyn_cast( - llvm::dyn_cast(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( - llvm::dyn_cast(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("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("genl_family"); - if (!genlFamily) { - return; - } - for (const auto &field : genlFamily->fields()) { - genlFamilyMember[field->getNameAsString()] = field->getFieldIndex(); - } const auto *genlFamilyInit = Result.Nodes.getNodeAs("genl_family_init"); if (!genlFamilyInit) { return; } + if (genlFamilyMember.empty()) { + const auto *genlFamily = Result.Nodes.getNodeAs("genl_family"); + for (const auto &field : genlFamily->fields()) { + genlFamilyMember[field->getNameAsString()] = field->getFieldIndex(); + } + } auto name = llvm::dyn_cast(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()); } -- cgit mrf-deployment