diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2025-01-17 10:39:49 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2025-01-22 17:12:18 +0000 |
| commit | 8aaf5d60aa0b3ddb05e117f52c0e30ec246b7aad (patch) | |
| tree | 63ddc4520d1e4b865925a014d3401b5e15c1fed3 /tools | |
| parent | ac680c7cc91ea82316471433537f3101c2af39ea (diff) | |
tools/syz-declextract: support function scopes
Extract info about function scopes formed by switch'es on function arguments.
For example if we have:
void foo(..., int cmd, ...)
{
...
switch (cmd) {
case FOO:
... block 1 ...
case BAR:
... block 2 ...
}
...
}
We record that any data flow within block 1 is only relevant
when foo's arg cmd has value FOO, similarly for block 2 and BAR.
This allows to do 3 things:
1. Locate ioctl commands that are switched on within transitively
called functions.
2. Infer return value for each ioctl command.
3. Infer argument type when it's not specified in _IO macro.
This will also allow to infer other multiplexed syscalls.
Descriptions generated on Linux commit c4b9570cfb63501.
Diffstat (limited to 'tools')
18 files changed, 1283 insertions, 507 deletions
diff --git a/tools/syz-declextract/clangtool/declextract.cpp b/tools/syz-declextract/clangtool/declextract.cpp index d7d6bc824..98d2342e8 100644 --- a/tools/syz-declextract/clangtool/declextract.cpp +++ b/tools/syz-declextract/clangtool/declextract.cpp @@ -12,6 +12,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -32,8 +33,10 @@ #include <cstddef> #include <cstdint> #include <filesystem> +#include <stack> #include <string> #include <string_view> +#include <tuple> #include <unordered_map> #include <vector> @@ -49,6 +52,13 @@ struct MacroDef { }; using MacroMap = std::unordered_map<std::string, MacroDef>; +struct MacroDesc { + std::string Name; + std::string Value; + SourceRange SourceRange; + int64_t IntValue; +}; + class Extractor : public MatchFinder, public tooling::SourceFileCallbacks { public: Extractor() { @@ -80,6 +90,7 @@ public: void print() const { Output.print(); } private: + friend struct FunctionAnalyzer; using MatchFunc = void (Extractor::*)(); // Thunk that redirects MatchCallback::run method to one of the methods of the Extractor class. struct MatchCallbackThunk : MatchFinder::MatchCallback { @@ -129,13 +140,9 @@ private: std::optional<QualType> getSizeofType(const Expr* E); int sizeofType(const Type* T); int alignofType(const Type* T); - std::vector<IoctlCmd> extractIoctlCommands(const std::string& Ioctl); - std::optional<TypingEntity> getTypingEntity(const std::string& CurrentFunc, - std::unordered_map<const VarDecl*, int>& LocalVars, - std::unordered_map<std::string, int>& LocalSeq, const Expr* E); - std::optional<TypingEntity> getDeclTypingEntity(const std::string& CurrentFunc, - std::unordered_map<const VarDecl*, int>& LocalVars, - std::unordered_map<std::string, int>& LocalSeq, const Decl* Decl); + void extractIoctl(const Expr* Cmd, const MacroDesc& Macro); + int getStmtLOC(const Stmt* S); + std::optional<MacroDesc> isMacroRef(const Expr* E); }; // PPCallbacksTracker records all macro definitions (name/value/source location). @@ -343,6 +350,29 @@ std::string Extractor::getDeclFileID(const Decl* Decl) { return file; } +int Extractor::getStmtLOC(const Stmt* S) { + return std::max<int>(0, SourceManager->getExpansionLineNumber(S->getSourceRange().getEnd()) - + SourceManager->getExpansionLineNumber(S->getSourceRange().getBegin()) - 1); +} + +std::optional<MacroDesc> Extractor::isMacroRef(const Expr* E) { + if (!E) + return {}; + auto Range = Lexer::getAsCharRange(E->getSourceRange(), *SourceManager, Context->getLangOpts()); + const std::string& Str = Lexer::getSourceText(Range, *SourceManager, Context->getLangOpts()).str(); + auto MacroDef = Macros.find(Str); + if (MacroDef == Macros.end()) + return {}; + int64_t Val = evaluate(E); + emitConst(Str, Val, MacroDef->second.SourceRange.getBegin()); + return MacroDesc{ + .Name = Str, + .Value = MacroDef->second.Value, + .SourceRange = MacroDef->second.SourceRange, + .IntValue = Val, + }; +} + template <typename Node> void matchHelper(MatchFinder& Finder, ASTContext* Context, const Node* Expr) { Finder.match(*Expr, *Context); } @@ -587,78 +617,179 @@ bool isInterestingCall(const CallExpr* Call) { return true; } -void Extractor::matchFunctionDef() { - const auto* Func = getResult<FunctionDecl>("function"); - const std::string& CurrentFunc = Func->getNameAsString(); - const auto Range = Func->getSourceRange(); - const std::string& SourceFile = - std::filesystem::relative(SourceManager->getFilename(SourceManager->getExpansionLoc(Range.getBegin())).str()); - const int LOC = std::max<int>(0, SourceManager->getExpansionLineNumber(Range.getEnd()) - - SourceManager->getExpansionLineNumber(Range.getBegin()) - 1); - std::vector<TypingFact> Facts; - std::vector<std::string> Callees; - std::unordered_set<std::string> CalleesDedup; - std::unordered_map<const VarDecl*, int> LocalVars; - std::unordered_map<std::string, int> LocalSeq; - const auto& Calls = findAllMatches<CallExpr>(Func->getBody(), stmt(forEachDescendant(callExpr().bind("res")))); - for (auto* Call : Calls) { - if (!isInterestingCall(Call)) - continue; - const std::string& Callee = Call->getDirectCallee()->getNameAsString(); - for (unsigned AI = 0; AI < Call->getNumArgs(); AI++) { - if (auto Src = getTypingEntity(CurrentFunc, LocalVars, LocalSeq, Call->getArg(AI))) { - Facts.push_back({std::move(*Src), EntityArgument{ - .Func = Callee, - .Arg = AI, - }}); +struct FunctionAnalyzer : RecursiveASTVisitor<FunctionAnalyzer> { + FunctionAnalyzer(Extractor* Extractor, const FunctionDecl* Func) + : Extractor(Extractor), CurrentFunc(Func->getNameAsString()), Context(Extractor->Context), + SourceManager(Extractor->SourceManager) { + // The global function scope. + Scopes.push_back(FunctionScope{.Arg = -1, .LOC = Extractor->getStmtLOC(Func->getBody())}); + Current = &Scopes[0]; + TraverseStmt(Func->getBody()); + } + + bool VisitBinaryOperator(const BinaryOperator* B) { + if (B->isAssignmentOp()) + noteFact(getTypingEntity(B->getRHS()), getTypingEntity(B->getLHS())); + return true; + } + + bool VisitVarDecl(const VarDecl* D) { + if (D->getStorageDuration() == SD_Automatic) + noteFact(getTypingEntity(D->getInit()), getDeclTypingEntity(D)); + return true; + } + + bool VisitReturnStmt(const ReturnStmt* Ret) { + noteFact(getTypingEntity(Ret->getRetValue()), EntityReturn{.Func = CurrentFunc}); + return true; + } + + bool VisitCallExpr(const CallExpr* Call) { + if (isInterestingCall(Call)) { + const std::string& Callee = Call->getDirectCallee()->getNameAsString(); + Current->Calls.push_back(Callee); + for (unsigned AI = 0; AI < Call->getNumArgs(); AI++) { + noteFact(getTypingEntity(Call->getArg(AI)), EntityArgument{ + .Func = Callee, + .Arg = AI, + }); } } - if (!CalleesDedup.insert(Callee).second) - continue; - Callees.push_back(Callee); + return true; } - const auto& Assignments = findAllMatches<BinaryOperator>( - Func->getBody(), stmt(forEachDescendant(binaryOperator(isAssignmentOperator()).bind("res")))); - for (auto* A : Assignments) { - auto Src = getTypingEntity(CurrentFunc, LocalVars, LocalSeq, A->getRHS()); - auto Dst = getTypingEntity(CurrentFunc, LocalVars, LocalSeq, A->getLHS()); - if (Src && Dst) - Facts.push_back({std::move(*Src), std::move(*Dst)}); + + bool VisitSwitchStmt(const SwitchStmt* S) { + // We are only interested in switches on the function arguments + // with cases that mention defines from uapi headers. + // This covers ioctl/fcntl/prctl/ptrace/etc. + bool IsInteresting = false; + auto Param = getTypingEntity(S->getCond()); + if (Current == &Scopes[0] && Param && Param->Argument) { + for (auto* C = S->getSwitchCaseList(); C; C = C->getNextSwitchCase()) { + auto* Case = dyn_cast<CaseStmt>(C); + if (!Case) + continue; + auto LMacro = Extractor->isMacroRef(Case->getLHS()); + auto RMacro = Extractor->isMacroRef(Case->getRHS()); + if (LMacro || RMacro) { + IsInteresting = true; + break; + } + } + } + + int Begin = SourceManager->getExpansionLineNumber(S->getBeginLoc()); + int End = SourceManager->getExpansionLineNumber(S->getEndLoc()); + if (IsInteresting) + Scopes[0].LOC = std::max<int>(0, Scopes[0].LOC - (End - Begin)); + SwitchStack.push({S, IsInteresting, IsInteresting ? static_cast<int>(Param->Argument->Arg) : -1, End}); + return true; } - const auto& VarDecls = findAllMatches<VarDecl>( - Func->getBody(), stmt(forEachDescendant(varDecl(hasAutomaticStorageDuration()).bind("res")))); - for (auto* D : VarDecls) { - auto Src = getTypingEntity(CurrentFunc, LocalVars, LocalSeq, D->getInit()); - auto Dst = getDeclTypingEntity(CurrentFunc, LocalVars, LocalSeq, D); - if (Src && Dst) - Facts.push_back({std::move(*Src), std::move(*Dst)}); - } - const auto& Returns = findAllMatches<ReturnStmt>(Func->getBody(), stmt(forEachDescendant(returnStmt().bind("res")))); - for (auto* Ret : Returns) { - if (auto Src = getTypingEntity(CurrentFunc, LocalVars, LocalSeq, Ret->getRetValue())) { - Facts.push_back({std::move(*Src), EntityReturn{ - .Func = CurrentFunc, - }}); + + bool VisitSwitchCase(const SwitchCase* C) { + if (!SwitchStack.top().IsInteresting) + return true; + // If there are several cases with the same "body", we want to create new scope + // only for the first one: + // case FOO: + // case BAR: + // ... some code ... + if (!C->getNextSwitchCase() || C->getNextSwitchCase()->getSubStmt() != C) { + int Line = SourceManager->getExpansionLineNumber(C->getBeginLoc()); + if (Current != &Scopes[0]) + Current->LOC = Line - Current->LOC; + Scopes.push_back(FunctionScope{ + .Arg = SwitchStack.top().Arg, + .LOC = Line, + }); + Current = &Scopes.back(); + } + // Otherwise it's a default case, for which we don't add any values. + if (auto* Case = dyn_cast<CaseStmt>(C)) { + int64_t LVal = Extractor->evaluate(Case->getLHS()); + auto LMacro = Extractor->isMacroRef(Case->getLHS()); + if (LMacro) { + Current->Values.push_back(LMacro->Name); + Extractor->extractIoctl(Case->getLHS(), *LMacro); + } else { + Current->Values.push_back(std::to_string(LVal)); + } + if (Case->caseStmtIsGNURange()) { + // GNU range is: + // case FOO ... BAR: + // Add all values in the range. + int64_t RVal = Extractor->evaluate(Case->getRHS()); + auto RMacro = Extractor->isMacroRef(Case->getRHS()); + for (int64_t V = LVal + 1; V <= RVal - (RMacro ? 1 : 0); V++) + Current->Values.push_back(std::to_string(V)); + if (RMacro) + Current->Values.push_back(RMacro->Name); + } } + return true; + } + + bool dataTraverseStmtPost(const Stmt* S) { + if (SwitchStack.empty()) + return true; + auto Top = SwitchStack.top(); + if (Top.S != S) + return true; + if (Top.IsInteresting) { + Current->LOC = Top.EndLine - Current->LOC; + Current = &Scopes[0]; + } + SwitchStack.pop(); + return true; + } + + void noteFact(std::optional<TypingEntity>&& Src, std::optional<TypingEntity>&& Dst) { + if (Src && Dst) + Current->Facts.push_back({std::move(*Src), std::move(*Dst)}); } + + std::optional<TypingEntity> getTypingEntity(const Expr* E); + std::optional<TypingEntity> getDeclTypingEntity(const Decl* Decl); + + struct SwitchDesc { + const SwitchStmt* S; + bool IsInteresting; + int Arg; + int EndLine; + }; + + Extractor* Extractor; + std::string CurrentFunc; + ASTContext* Context; + SourceManager* SourceManager; + std::vector<FunctionScope> Scopes; + FunctionScope* Current = nullptr; + std::unordered_map<const VarDecl*, int> LocalVars; + std::unordered_map<std::string, int> LocalSeq; + std::stack<SwitchDesc> SwitchStack; +}; + +void Extractor::matchFunctionDef() { + const auto* Func = getResult<FunctionDecl>("function"); + if (!Func->getBody()) + return; + const std::string& SourceFile = std::filesystem::relative( + SourceManager->getFilename(SourceManager->getExpansionLoc(Func->getSourceRange().getBegin())).str()); + FunctionAnalyzer Analyzer(this, Func); Output.emit(Function{ - .Name = CurrentFunc, + .Name = Func->getNameAsString(), .File = SourceFile, .IsStatic = Func->isStatic(), - .LOC = LOC, - .Calls = std::move(Callees), - .Facts = std::move(Facts), + .Scopes = std::move(Analyzer.Scopes), }); } -std::optional<TypingEntity> Extractor::getTypingEntity(const std::string& CurrentFunc, - std::unordered_map<const VarDecl*, int>& LocalVars, - std::unordered_map<std::string, int>& LocalSeq, const Expr* E) { +std::optional<TypingEntity> FunctionAnalyzer::getTypingEntity(const Expr* E) { if (!E) return {}; E = removeCasts(E); if (auto* DeclRef = dyn_cast<DeclRefExpr>(E)) { - return getDeclTypingEntity(CurrentFunc, LocalVars, LocalSeq, DeclRef->getDecl()); + return getDeclTypingEntity(DeclRef->getDecl()); } else if (auto* Member = dyn_cast<MemberExpr>(E)) { const Type* StructType = Member->getBase()->getType().IgnoreParens().getUnqualifiedType().getDesugaredType(*Context).getTypePtr(); @@ -692,7 +823,7 @@ std::optional<TypingEntity> Extractor::getTypingEntity(const std::string& Curren if (auto* Var = dyn_cast<VarDecl>(DeclRef->getDecl())) { if (Var->hasGlobalStorage()) { return EntityGlobalAddr{ - .Name = getUniqueDeclName(Var), + .Name = Extractor->getUniqueDeclName(Var), }; } } @@ -708,10 +839,7 @@ std::optional<TypingEntity> Extractor::getTypingEntity(const std::string& Curren return {}; } -std::optional<TypingEntity> Extractor::getDeclTypingEntity(const std::string& CurrentFunc, - std::unordered_map<const VarDecl*, int>& LocalVars, - std::unordered_map<std::string, int>& LocalSeq, - const Decl* Decl) { +std::optional<TypingEntity> FunctionAnalyzer::getDeclTypingEntity(const Decl* Decl) { if (auto* Parm = dyn_cast<ParmVarDecl>(Decl)) { return EntityArgument{ .Func = CurrentFunc, @@ -790,7 +918,6 @@ void Extractor::matchFileOps() { std::string Mmap = getDeclName(Fops->getInit(Fields["mmap"])); if (Mmap.empty()) Mmap = getDeclName(Fops->getInit(Fields["get_unmapped_area"])); - auto Cmds = extractIoctlCommands(Ioctl); Output.emit(FileOps{ .Name = VarName, .Open = std::move(Open), @@ -798,47 +925,32 @@ void Extractor::matchFileOps() { .Write = std::move(Write), .Mmap = std::move(Mmap), .Ioctl = std::move(Ioctl), - .IoctlCmds = std::move(Cmds), }); } -std::vector<IoctlCmd> Extractor::extractIoctlCommands(const std::string& Ioctl) { - if (Ioctl.empty()) - return {}; - // If we see the ioctl function definition, match cases of switches (very best-effort for now). - const auto& Cases = findAllMatches<CaseStmt>( - Context, functionDecl(hasName(Ioctl), forEachDescendant(switchStmt(forEachSwitchCase(caseStmt().bind("res")))))); - std::vector<IoctlCmd> Results; - for (auto* Case : Cases) { - const auto* Cmd = Case->getLHS(); - auto Range = Lexer::getAsCharRange(Cmd->getSourceRange(), *SourceManager, Context->getLangOpts()); - std::string CmdStr = Lexer::getSourceText(Range, *SourceManager, Context->getLangOpts()).str(); - auto MacroDef = Macros.find(CmdStr); - if (MacroDef == Macros.end()) - continue; - int64_t CmdVal = evaluate(Cmd); - emitConst(CmdStr, CmdVal, MacroDef->second.SourceRange.getBegin()); - FieldType CmdType; - const auto Dir = _IOC_DIR(CmdVal); - if (Dir == _IOC_NONE) { - CmdType = IntType{.ByteSize = 1, .IsConst = true}; - } else if (std::optional<QualType> Arg = getSizeofType(Cmd)) { - CmdType = PtrType{ - .Elem = genType(*Arg), - .IsConst = Dir == _IOC_READ, - }; - } else { - CmdType = PtrType{ - .Elem = BufferType{}, - .IsConst = Dir == _IOC_READ, - }; - } - Results.push_back(IoctlCmd{ - .Name = CmdStr, - .Type = std::move(CmdType), - }); +void Extractor::extractIoctl(const Expr* Cmd, const MacroDesc& Macro) { + // This is old style ioctl defined directly via a number. + // We can't infer anything about it. + if (Macro.Value.find("_IO") != 0) + return; + FieldType Type; + auto Dir = _IOC_DIR(Macro.IntValue); + if (Dir == _IOC_NONE) { + Type = IntType{.ByteSize = 1, .IsConst = true}; + } else if (std::optional<QualType> Arg = getSizeofType(Cmd)) { + Type = PtrType{ + .Elem = genType(*Arg), + .IsConst = Dir == _IOC_READ, + }; + } else { + // It is an ioctl, but we failed to get the arg type. + // Let the Go part figure out a good arg type. + return; } - return Results; + Output.emit(Ioctl{ + .Name = Macro.Name, + .Type = std::move(Type), + }); } int main(int argc, const char** argv) { diff --git a/tools/syz-declextract/clangtool/output.h b/tools/syz-declextract/clangtool/output.h index ffa0844c9..4a482ed3c 100644 --- a/tools/syz-declextract/clangtool/output.h +++ b/tools/syz-declextract/clangtool/output.h @@ -93,7 +93,7 @@ struct Enum { std::vector<std::string> Values; }; -struct IoctlCmd { +struct Ioctl { std::string Name; FieldType Type; }; @@ -105,7 +105,6 @@ struct FileOps { std::string Write; std::string Mmap; std::string Ioctl; - std::vector<IoctlCmd> IoctlCmds; }; struct EntityReturn { @@ -157,13 +156,19 @@ struct TypingFact { TypingEntity Dst; }; +struct FunctionScope { + int Arg = 0; + int LOC = 0; + std::vector<std::string> Values; + std::vector<std::string> Calls; + std::vector<TypingFact> Facts; +}; + struct Function { std::string Name; std::string File; bool IsStatic = false; - int LOC = 0; - std::vector<std::string> Calls; - std::vector<TypingFact> Facts; + std::vector<FunctionScope> Scopes; }; struct Syscall { @@ -282,7 +287,7 @@ inline void print(JSONPrinter& Printer, const BufferType& V) { Printer.Field("is_non_terminated", V.IsNonTerminated, true); } -inline void print(JSONPrinter& Printer, const IoctlCmd& V) { +inline void print(JSONPrinter& Printer, const Ioctl& V) { JSONPrinter::Scope Scope(Printer); Printer.Field("name", V.Name); Printer.Field("type", V.Type, true); @@ -295,8 +300,7 @@ inline void print(JSONPrinter& Printer, const FileOps& V) { Printer.Field("read", V.Read); Printer.Field("write", V.Write); Printer.Field("mmap", V.Mmap); - Printer.Field("ioctl", V.Ioctl); - Printer.Field("ioctl_cmds", V.IoctlCmds, true); + Printer.Field("ioctl", V.Ioctl, true); } inline void print(JSONPrinter& Printer, const EntityReturn& V) { @@ -354,14 +358,21 @@ inline void print(JSONPrinter& Printer, const TypingFact& V) { Printer.Field("dst", V.Dst, true); } +inline void print(JSONPrinter& Printer, const FunctionScope& V) { + JSONPrinter::Scope Scope(Printer); + Printer.Field("arg", V.Arg); + Printer.Field("values", V.Values); + Printer.Field("loc", V.LOC); + Printer.Field("calls", V.Calls); + Printer.Field("facts", V.Facts, true); +} + inline void print(JSONPrinter& Printer, const Function& V) { JSONPrinter::Scope Scope(Printer); Printer.Field("name", V.Name); Printer.Field("file", V.File); Printer.Field("is_static", V.IsStatic); - Printer.Field("loc", V.LOC); - Printer.Field("calls", V.Calls); - Printer.Field("facts", V.Facts, true); + Printer.Field("scopes", V.Scopes, true); } inline void print(JSONPrinter& Printer, const Syscall& V) { @@ -422,6 +433,7 @@ public: void emit(Enum&& V) { Enums.push_back(std::move(V)); } void emit(Syscall&& V) { Syscalls.push_back(std::move(V)); } void emit(FileOps&& V) { FileOps.push_back(std::move(V)); } + void emit(Ioctl&& V) { Ioctls.push_back(std::move(V)); } void emit(IouringOp&& V) { IouringOps.push_back(std::move(V)); } void emit(NetlinkFamily&& V) { NetlinkFamilies.push_back(std::move(V)); } void emit(NetlinkPolicy&& V) { NetlinkPolicies.push_back(std::move(V)); } @@ -434,6 +446,7 @@ public: Printer.Field("structs", Structs); Printer.Field("syscalls", Syscalls); Printer.Field("file_ops", FileOps); + Printer.Field("ioctls", Ioctls); Printer.Field("iouring_ops", IouringOps); Printer.Field("netlink_families", NetlinkFamilies); Printer.Field("netlink_policies", NetlinkPolicies, true); @@ -446,6 +459,7 @@ private: std::vector<Struct> Structs; std::vector<Syscall> Syscalls; std::vector<FileOps> FileOps; + std::vector<Ioctl> Ioctls; std::vector<IouringOp> IouringOps; std::vector<NetlinkFamily> NetlinkFamilies; std::vector<NetlinkPolicy> NetlinkPolicies; diff --git a/tools/syz-declextract/testdata/arch/x86/syscalls.tbl b/tools/syz-declextract/testdata/arch/x86/syscalls.tbl index 7f728f3f2..605db1316 100644 --- a/tools/syz-declextract/testdata/arch/x86/syscalls.tbl +++ b/tools/syz-declextract/testdata/arch/x86/syscalls.tbl @@ -6,3 +6,5 @@ 3 64 types_syscall sys_types_syscall 4 64 align_syscall sys_align_syscall 5 64 functions sys_functions +6 64 scopes0 sys_scopes0 + diff --git a/tools/syz-declextract/testdata/file_operations.c b/tools/syz-declextract/testdata/file_operations.c index 0dd8b9b21..136e608dd 100644 --- a/tools/syz-declextract/testdata/file_operations.c +++ b/tools/syz-declextract/testdata/file_operations.c @@ -10,7 +10,15 @@ static void foo_read() {} static void foo_write() {} static void foo_mmap() {} -static void foo_ioctl(unsigned int cmd) { +static void foo_ioctl2(unsigned int cmd, unsigned long arg) { + switch (cmd) { + case FOO_IOCTL6: + case FOO_IOCTL7: + default: + } +} + +static void foo_ioctl(void* file, unsigned int cmd, unsigned long arg) { switch (cmd) { case FOO_IOCTL1: case FOO_IOCTL2: @@ -18,6 +26,7 @@ static void foo_ioctl(unsigned int cmd) { case FOO_IOCTL4: case FOO_IOCTL5: } + foo_ioctl2(cmd, arg); } const struct file_operations foo = { @@ -31,7 +40,7 @@ const struct file_operations foo = { static void proc_open() {} static void proc_read() {} static void proc_write() {} -static void proc_ioctl(unsigned int cmd) {} +static void proc_ioctl(void* file, unsigned int cmd, unsigned long arg) {} const struct file_operations proc_ops[] = { { @@ -47,7 +56,7 @@ const struct file_operations proc_ops[] = { #define UNUSED_IOCTL2 _IO('c', 2) -static void unused_ioctl(unsigned int cmd) { +static void unused_ioctl(void* file, unsigned int cmd, unsigned long arg) { switch (cmd) { case UNUSED_IOCTL1: case UNUSED_IOCTL2: diff --git a/tools/syz-declextract/testdata/file_operations.c.json b/tools/syz-declextract/testdata/file_operations.c.json index c8fd5a9dc..e7dfd31f6 100644 --- a/tools/syz-declextract/testdata/file_operations.c.json +++ b/tools/syz-declextract/testdata/file_operations.c.json @@ -4,53 +4,174 @@ "name": "foo_ioctl", "file": "file_operations.c", "is_static": true, - "loc": 7 + "scopes": [ + { + "arg": -1, + "loc": 2, + "calls": [ + "foo_ioctl2" + ], + "facts": [ + { + "src": { + "argument": { + "func": "foo_ioctl", + "arg": 1 + } + }, + "dst": { + "argument": { + "func": "foo_ioctl2", + "arg": 0 + } + } + }, + { + "src": { + "argument": { + "func": "foo_ioctl", + "arg": 2 + } + }, + "dst": { + "argument": { + "func": "foo_ioctl2", + "arg": 1 + } + } + } + ] + }, + { + "arg": 1, + "values": [ + "FOO_IOCTL1", + "FOO_IOCTL2", + "FOO_IOCTL3", + "FOO_IOCTL4", + "FOO_IOCTL5" + ], + "loc": 5 + } + ] + }, + { + "name": "foo_ioctl2", + "file": "file_operations.c", + "is_static": true, + "scopes": [ + { + "arg": -1, + "loc": 1 + }, + { + "arg": 0, + "values": [ + "FOO_IOCTL6", + "FOO_IOCTL7" + ], + "loc": 3 + } + ] }, { "name": "foo_mmap", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "foo_open", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "foo_read", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "foo_write", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "proc_ioctl", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "proc_open", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "proc_read", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "proc_write", "file": "file_operations.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "unused_ioctl", "file": "file_operations.c", "is_static": true, - "loc": 4 + "scopes": [ + { + "arg": -1, + "loc": 1 + }, + { + "arg": 1, + "values": [ + "UNUSED_IOCTL1", + "UNUSED_IOCTL2" + ], + "loc": 2 + } + ] } ], "consts": [ @@ -80,6 +201,16 @@ "value": 3221775109 }, { + "name": "FOO_IOCTL6", + "filename": "include/uapi/file_operations.h", + "value": 25350 + }, + { + "name": "FOO_IOCTL7", + "filename": "include/uapi/file_operations.h", + "value": 25351 + }, + { "name": "UNUSED_IOCTL1", "filename": "include/uapi/unused_ioctl.h", "value": 25345 @@ -129,63 +260,6 @@ "write": "foo_write", "mmap": "foo_mmap", "ioctl": "foo_ioctl", - "ioctl_cmds": [ - { - "name": "FOO_IOCTL5", - "type": { - "ptr": { - "elem": { - "struct": "foo_ioctl_arg" - } - } - } - }, - { - "name": "FOO_IOCTL4", - "type": { - "ptr": { - "elem": { - "struct": "foo_ioctl_arg" - } - } - } - }, - { - "name": "FOO_IOCTL3", - "type": { - "ptr": { - "elem": { - "struct": "foo_ioctl_arg" - }, - "is_const": true - } - } - }, - { - "name": "FOO_IOCTL2", - "type": { - "ptr": { - "elem": { - "int": { - "byte_size": 4, - "name": "int", - "base": "int" - } - }, - "is_const": true - } - } - }, - { - "name": "FOO_IOCTL1", - "type": { - "int": { - "byte_size": 1, - "is_const": true - } - } - } - ], "source_file": "file_operations.c" }, { @@ -206,27 +280,100 @@ { "name": "unused_file_operations", "ioctl": "unused_ioctl", - "ioctl_cmds": [ - { - "name": "UNUSED_IOCTL2", - "type": { + "source_file": "file_operations.c" + } + ], + "ioctls": [ + { + "name": "FOO_IOCTL1", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } + }, + { + "name": "FOO_IOCTL2", + "type": { + "ptr": { + "elem": { "int": { - "byte_size": 1, - "is_const": true + "byte_size": 4, + "name": "int", + "base": "int" } + }, + "is_const": true + } + } + }, + { + "name": "FOO_IOCTL3", + "type": { + "ptr": { + "elem": { + "struct": "foo_ioctl_arg" + }, + "is_const": true + } + } + }, + { + "name": "FOO_IOCTL4", + "type": { + "ptr": { + "elem": { + "struct": "foo_ioctl_arg" } - }, - { - "name": "UNUSED_IOCTL1", - "type": { - "int": { - "byte_size": 1, - "is_const": true - } + } + } + }, + { + "name": "FOO_IOCTL5", + "type": { + "ptr": { + "elem": { + "struct": "foo_ioctl_arg" } } - ], - "source_file": "file_operations.c" + } + }, + { + "name": "FOO_IOCTL6", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } + }, + { + "name": "FOO_IOCTL7", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } + }, + { + "name": "UNUSED_IOCTL1", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } + }, + { + "name": "UNUSED_IOCTL2", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } } ] }
\ No newline at end of file diff --git a/tools/syz-declextract/testdata/file_operations.c.txt b/tools/syz-declextract/testdata/file_operations.c.txt index e94856980..f37a386db 100644 --- a/tools/syz-declextract/testdata/file_operations.c.txt +++ b/tools/syz-declextract/testdata/file_operations.c.txt @@ -6,6 +6,7 @@ type auto_todo int8 include <vdso/bits.h> include <linux/types.h> +include <linux/usbdevice_fs.h> include <include/uapi/file_operations.h> resource fd_foo_file_operations[fd] @@ -18,6 +19,8 @@ ioctl$auto_FOO_IOCTL2(fd fd_foo_file_operations, cmd const[FOO_IOCTL2], arg ptr[ ioctl$auto_FOO_IOCTL3(fd fd_foo_file_operations, cmd const[FOO_IOCTL3], arg ptr[in, foo_ioctl_arg$auto]) ioctl$auto_FOO_IOCTL4(fd fd_foo_file_operations, cmd const[FOO_IOCTL4], arg ptr[inout, foo_ioctl_arg$auto]) ioctl$auto_FOO_IOCTL5(fd fd_foo_file_operations, cmd const[FOO_IOCTL5], arg ptr[inout, foo_ioctl_arg$auto]) +ioctl$auto_FOO_IOCTL6(fd fd_foo_file_operations, cmd const[FOO_IOCTL6], arg const[0]) +ioctl$auto_FOO_IOCTL7(fd fd_foo_file_operations, cmd const[FOO_IOCTL7], arg const[0]) foo_ioctl_arg$auto { a int32 diff --git a/tools/syz-declextract/testdata/functions.c.json b/tools/syz-declextract/testdata/functions.c.json index eb1b3b880..ecb95affc 100644 --- a/tools/syz-declextract/testdata/functions.c.json +++ b/tools/syz-declextract/testdata/functions.c.json @@ -3,256 +3,317 @@ { "name": "__do_sys_functions", "file": "functions.c", - "loc": 2, - "calls": [ - "__fget_light", - "func_baz" - ], - "facts": [ - { - "src": { - "argument": { - "func": "__do_sys_functions", - "arg": 0 - } - }, - "dst": { - "argument": { - "func": "__fget_light", - "arg": 0 - } - } - }, + "scopes": [ { - "src": { - "return": { - "func": "func_baz" + "arg": -1, + "loc": 2, + "calls": [ + "__fget_light", + "func_baz" + ], + "facts": [ + { + "src": { + "argument": { + "func": "__do_sys_functions", + "arg": 0 + } + }, + "dst": { + "argument": { + "func": "__fget_light", + "arg": 0 + } + } + }, + { + "src": { + "return": { + "func": "func_baz" + } + }, + "dst": { + "return": { + "func": "__do_sys_functions" + } + } } - }, - "dst": { - "return": { - "func": "__do_sys_functions" - } - } + ] } ] }, { "name": "__fget_light", - "file": "functions.c" + "file": "functions.c", + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "alloc_fd", "file": "functions.c", - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "atomic_load32", "file": "include/types.h", "is_static": true, - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "atomic_load64", "file": "include/types.h", - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "from_kuid", "file": "functions.c", - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "func_bar", "file": "functions.c", "is_static": true, - "loc": 1, - "calls": [ - "func_foo" + "scopes": [ + { + "arg": -1, + "loc": 1, + "calls": [ + "func_foo" + ] + } ] }, { "name": "func_baz", "file": "functions.c", - "loc": 8, - "calls": [ - "func_foo", - "func_bar", - "from_kuid", - "alloc_fd" - ], - "facts": [ + "scopes": [ { - "src": { - "return": { - "func": "from_kuid" + "arg": -1, + "loc": 8, + "calls": [ + "func_foo", + "func_bar", + "func_bar", + "from_kuid", + "alloc_fd" + ], + "facts": [ + { + "src": { + "return": { + "func": "from_kuid" + } + }, + "dst": { + "return": { + "func": "func_baz" + } + } + }, + { + "src": { + "return": { + "func": "alloc_fd" + } + }, + "dst": { + "return": { + "func": "func_baz" + } + } } - }, - "dst": { - "return": { - "func": "func_baz" - } - } - }, - { - "src": { - "return": { - "func": "alloc_fd" - } - }, - "dst": { - "return": { - "func": "func_baz" - } - } + ] } ] }, { "name": "func_foo", "file": "functions.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "func_qux", "file": "functions.c", - "loc": 2, - "calls": [ - "alloc_fd" - ], - "facts": [ + "scopes": [ { - "src": { - "return": { - "func": "alloc_fd" + "arg": -1, + "loc": 2, + "calls": [ + "alloc_fd" + ], + "facts": [ + { + "src": { + "return": { + "func": "alloc_fd" + } + }, + "dst": { + "local": { + "name": "fd" + } + } + }, + { + "src": { + "local": { + "name": "fd" + } + }, + "dst": { + "return": { + "func": "func_qux" + } + } } - }, - "dst": { - "local": { - "name": "fd" - } - } - }, - { - "src": { - "local": { - "name": "fd" - } - }, - "dst": { - "return": { - "func": "func_qux" - } - } + ] } ] }, { "name": "typing", "file": "functions.c", - "loc": 5, - "calls": [ - "typing1" - ], - "facts": [ - { - "src": { - "argument": { - "func": "typing", - "arg": 1 - } - }, - "dst": { - "argument": { - "func": "typing1", - "arg": 0 - } - } - }, - { - "src": { - "field": { - "struct": "Typed", - "field": "a" - } - }, - "dst": { - "argument": { - "func": "typing1", - "arg": 1 - } - } - }, - { - "src": { - "field": { - "struct": "Typed", - "field": "b" - } - }, - "dst": { - "field": { - "struct": "Typed", - "field": "a" - } - } - }, - { - "src": { - "local": { - "name": "l" - } - }, - "dst": { - "field": { - "struct": "Typed", - "field": "c" - } - } - }, + "scopes": [ { - "src": { - "return": { - "func": "typing1" + "arg": -1, + "loc": 5, + "calls": [ + "typing1" + ], + "facts": [ + { + "src": { + "field": { + "struct": "Typed", + "field": "b" + } + }, + "dst": { + "field": { + "struct": "Typed", + "field": "a" + } + } + }, + { + "src": { + "return": { + "func": "typing1" + } + }, + "dst": { + "local": { + "name": "l" + } + } + }, + { + "src": { + "argument": { + "func": "typing", + "arg": 1 + } + }, + "dst": { + "argument": { + "func": "typing1", + "arg": 0 + } + } + }, + { + "src": { + "field": { + "struct": "Typed", + "field": "a" + } + }, + "dst": { + "argument": { + "func": "typing1", + "arg": 1 + } + } + }, + { + "src": { + "local": { + "name": "l" + } + }, + "dst": { + "field": { + "struct": "Typed", + "field": "c" + } + } + }, + { + "src": { + "local": { + "name": "l" + } + }, + "dst": { + "return": { + "func": "typing" + } + } } - }, - "dst": { - "local": { - "name": "l" - } - } - }, - { - "src": { - "local": { - "name": "l" - } - }, - "dst": { - "return": { - "func": "typing" - } - } + ] } ] }, { "name": "typing1", "file": "functions.c", - "loc": 1, - "facts": [ + "scopes": [ { - "src": { - "argument": { - "func": "typing1", - "arg": 0 + "arg": -1, + "loc": 1, + "facts": [ + { + "src": { + "argument": { + "func": "typing1", + "arg": 0 + } + }, + "dst": { + "return": { + "func": "typing1" + } + } } - }, - "dst": { - "return": { - "func": "typing1" - } - } + ] } ] } diff --git a/tools/syz-declextract/testdata/include/fs.h b/tools/syz-declextract/testdata/include/fs.h index a5c838595..33782d1ee 100644 --- a/tools/syz-declextract/testdata/include/fs.h +++ b/tools/syz-declextract/testdata/include/fs.h @@ -7,6 +7,11 @@ struct file_operations { void (*write)(void); void (*read_iter)(void); void (*write_iter)(void); - void (*unlocked_ioctl)(unsigned int); + void (*unlocked_ioctl)(void*, unsigned int, unsigned long); void (*mmap)(void); }; + +int alloc_fd(); +void __fget_light(int fd); +int from_kuid(); + diff --git a/tools/syz-declextract/testdata/include/uapi/file_operations.h b/tools/syz-declextract/testdata/include/uapi/file_operations.h index 6a2a8d259..f81d6886d 100644 --- a/tools/syz-declextract/testdata/include/uapi/file_operations.h +++ b/tools/syz-declextract/testdata/include/uapi/file_operations.h @@ -8,6 +8,10 @@ #define FOO_IOCTL3 _IOR('c', 3, struct foo_ioctl_arg) #define FOO_IOCTL4 _IOW('c', 4, struct foo_ioctl_arg) #define FOO_IOCTL5 _IOWR('c', 5, struct foo_ioctl_arg) +#define FOO_IOCTL6 _IO('c', 6) +#define FOO_IOCTL7 _IO('c', 7) +#define FOO_IOCTL8 _IO('c', 8) +#define FOO_IOCTL9 _IO('c', 9) struct foo_ioctl_arg { int a, b; diff --git a/tools/syz-declextract/testdata/io_uring.c.json b/tools/syz-declextract/testdata/io_uring.c.json index da91ce1b6..60ac44818 100644 --- a/tools/syz-declextract/testdata/io_uring.c.json +++ b/tools/syz-declextract/testdata/io_uring.c.json @@ -2,31 +2,66 @@ "functions": [ { "name": "io_eopnotsupp_prep", - "file": "io_uring.c" + "file": "io_uring.c", + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "io_nop", - "file": "io_uring.c" + "file": "io_uring.c", + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "io_nop_prep", - "file": "io_uring.c" + "file": "io_uring.c", + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "io_read", - "file": "io_uring.c" + "file": "io_uring.c", + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "io_readv_prep", - "file": "io_uring.c" + "file": "io_uring.c", + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "io_write", - "file": "io_uring.c" + "file": "io_uring.c", + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "io_writev_prep", - "file": "io_uring.c" + "file": "io_uring.c", + "scopes": [ + { + "arg": -1 + } + ] } ], "consts": [ diff --git a/tools/syz-declextract/testdata/netlink.c.json b/tools/syz-declextract/testdata/netlink.c.json index 35b2a79b5..9571730f7 100644 --- a/tools/syz-declextract/testdata/netlink.c.json +++ b/tools/syz-declextract/testdata/netlink.c.json @@ -4,37 +4,72 @@ "name": "atomic_load32", "file": "include/types.h", "is_static": true, - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "atomic_load64", "file": "include/types.h", - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "bar_cmd", "file": "netlink.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "bar_doit", "file": "netlink.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "bar_post_doit", "file": "netlink.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "bar_pre_doit", "file": "netlink.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] }, { "name": "foo_cmd", "file": "netlink.c", - "is_static": true + "is_static": true, + "scopes": [ + { + "arg": -1 + } + ] } ], "consts": [ diff --git a/tools/syz-declextract/testdata/scopes.c b/tools/syz-declextract/testdata/scopes.c new file mode 100644 index 000000000..56c1638d1 --- /dev/null +++ b/tools/syz-declextract/testdata/scopes.c @@ -0,0 +1,30 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#include "include/fs.h" +#include "include/syscall.h" +#include "include/uapi/file_operations.h" + +SYSCALL_DEFINE1(scopes0, int x, long cmd, long aux) { + int tmp = 0; + __fget_light(aux); + switch (cmd) { + case FOO_IOCTL1: + __fget_light(x); + break; + case FOO_IOCTL2: + case FOO_IOCTL3: + tmp = alloc_fd(); + return tmp; + case FOO_IOCTL4 ... FOO_IOCTL4 + 2: + tmp++; + break; + case 100 ... 102: + tmp++; + break; + default: + tmp = cmd; + break; + } + return tmp; +} diff --git a/tools/syz-declextract/testdata/scopes.c.info b/tools/syz-declextract/testdata/scopes.c.info new file mode 100644 index 000000000..f3a8f9cf3 --- /dev/null +++ b/tools/syz-declextract/testdata/scopes.c.info @@ -0,0 +1 @@ +SYSCALL scopes0 func:__do_sys_scopes0 loc:20 access:unknown manual_desc:false auto_desc:true file:scopes.c subsystem:kernel diff --git a/tools/syz-declextract/testdata/scopes.c.json b/tools/syz-declextract/testdata/scopes.c.json new file mode 100644 index 000000000..2a497dbe1 --- /dev/null +++ b/tools/syz-declextract/testdata/scopes.c.json @@ -0,0 +1,286 @@ +{ + "functions": [ + { + "name": "__do_sys_scopes0", + "file": "scopes.c", + "scopes": [ + { + "arg": -1, + "loc": 4, + "calls": [ + "__fget_light" + ], + "facts": [ + { + "src": { + "argument": { + "func": "__do_sys_scopes0", + "arg": 2 + } + }, + "dst": { + "argument": { + "func": "__fget_light", + "arg": 0 + } + } + }, + { + "src": { + "local": { + "name": "tmp" + } + }, + "dst": { + "return": { + "func": "__do_sys_scopes0" + } + } + } + ] + }, + { + "arg": 1, + "values": [ + "FOO_IOCTL1" + ], + "loc": 3, + "calls": [ + "__fget_light" + ], + "facts": [ + { + "src": { + "argument": { + "func": "__do_sys_scopes0", + "arg": 0 + } + }, + "dst": { + "argument": { + "func": "__fget_light", + "arg": 0 + } + } + } + ] + }, + { + "arg": 1, + "values": [ + "FOO_IOCTL2", + "FOO_IOCTL3" + ], + "loc": 4, + "calls": [ + "alloc_fd" + ], + "facts": [ + { + "src": { + "return": { + "func": "alloc_fd" + } + }, + "dst": { + "local": { + "name": "tmp" + } + } + }, + { + "src": { + "local": { + "name": "tmp" + } + }, + "dst": { + "return": { + "func": "__do_sys_scopes0" + } + } + } + ] + }, + { + "arg": 1, + "values": [ + "FOO_IOCTL4", + "1074291461", + "1074291462" + ], + "loc": 3 + }, + { + "arg": 1, + "values": [ + "100", + "101", + "102" + ], + "loc": 3 + }, + { + "arg": 1, + "loc": 3, + "facts": [ + { + "src": { + "argument": { + "func": "__do_sys_scopes0", + "arg": 1 + } + }, + "dst": { + "local": { + "name": "tmp" + } + } + } + ] + } + ] + } + ], + "consts": [ + { + "name": "FOO_IOCTL1", + "filename": "include/uapi/file_operations.h", + "value": 25345 + }, + { + "name": "FOO_IOCTL2", + "filename": "include/uapi/file_operations.h", + "value": 2147771138 + }, + { + "name": "FOO_IOCTL3", + "filename": "include/uapi/file_operations.h", + "value": 2148033283 + }, + { + "name": "FOO_IOCTL4", + "filename": "include/uapi/file_operations.h", + "value": 1074291460 + } + ], + "structs": [ + { + "name": "foo_ioctl_arg", + "byte_size": 8, + "align": 4, + "fields": [ + { + "name": "a", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + } + ], + "syscalls": [ + { + "func": "__do_sys_scopes0", + "args": [ + { + "name": "x", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "cmd", + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "long", + "base": "long" + } + } + }, + { + "name": "aux", + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "long", + "base": "long" + } + } + } + ], + "source_file": "scopes.c" + } + ], + "ioctls": [ + { + "name": "FOO_IOCTL1", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } + }, + { + "name": "FOO_IOCTL2", + "type": { + "ptr": { + "elem": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + }, + "is_const": true + } + } + }, + { + "name": "FOO_IOCTL3", + "type": { + "ptr": { + "elem": { + "struct": "foo_ioctl_arg" + }, + "is_const": true + } + } + }, + { + "name": "FOO_IOCTL4", + "type": { + "ptr": { + "elem": { + "struct": "foo_ioctl_arg" + } + } + } + } + ] +}
\ No newline at end of file diff --git a/tools/syz-declextract/testdata/scopes.c.txt b/tools/syz-declextract/testdata/scopes.c.txt new file mode 100644 index 000000000..aec7f7f2d --- /dev/null +++ b/tools/syz-declextract/testdata/scopes.c.txt @@ -0,0 +1,7 @@ +# Code generated by syz-declextract. DO NOT EDIT. + +meta automatic + +type auto_todo int8 + +scopes0$auto(x int32, cmd intptr, aux intptr) diff --git a/tools/syz-declextract/testdata/syscall.c.json b/tools/syz-declextract/testdata/syscall.c.json index 735ac7dc9..4e466a3ae 100644 --- a/tools/syz-declextract/testdata/syscall.c.json +++ b/tools/syz-declextract/testdata/syscall.c.json @@ -3,12 +3,22 @@ { "name": "__do_sys_chmod", "file": "syscall.c", - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "__do_sys_open", "file": "syscall.c", - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] } ], "syscalls": [ diff --git a/tools/syz-declextract/testdata/types.c.info b/tools/syz-declextract/testdata/types.c.info index ac9903fbe..7c4e66ca1 100644 --- a/tools/syz-declextract/testdata/types.c.info +++ b/tools/syz-declextract/testdata/types.c.info @@ -1,2 +1,2 @@ SYSCALL align_syscall func:__do_sys_align_syscall loc:1 access:unknown manual_desc:false auto_desc:true file:types.c subsystem:kernel -SYSCALL types_syscall func:__do_sys_types_syscall loc:2 access:unknown manual_desc:false auto_desc:true file:types.c subsystem:kernel +SYSCALL types_syscall func:__do_sys_types_syscall loc:1 access:unknown manual_desc:false auto_desc:true file:types.c subsystem:kernel diff --git a/tools/syz-declextract/testdata/types.c.json b/tools/syz-declextract/testdata/types.c.json index 6c479dffb..90d3be2a9 100644 --- a/tools/syz-declextract/testdata/types.c.json +++ b/tools/syz-declextract/testdata/types.c.json @@ -3,115 +3,130 @@ { "name": "__do_sys_align_syscall", "file": "types.c", - "loc": 1 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "__do_sys_types_syscall", "file": "types.c", - "loc": 2 + "scopes": [ + { + "arg": -1, + "loc": 1 + } + ] }, { "name": "anon_flow", "file": "types.c", - "loc": 8, - "facts": [ - { - "src": { - "argument": { - "func": "anon_flow", - "arg": 0 - } - }, - "dst": { - "field": { - "struct": "11253655576479126316", - "field": "x" - } - } - }, - { - "src": { - "argument": { - "func": "anon_flow", - "arg": 0 - } - }, - "dst": { - "field": { - "struct": "11253655576479126318", - "field": "y" - } - } - }, - { - "src": { - "argument": { - "func": "anon_flow", - "arg": 0 - } - }, - "dst": { - "field": { - "struct": "11253655576479126319", - "field": "w" - } - } - }, - { - "src": { - "argument": { - "func": "anon_flow", - "arg": 0 - } - }, - "dst": { - "field": { - "struct": "11253655576479126309", - "field": "f" - } - } - }, - { - "src": { - "argument": { - "func": "anon_flow", - "arg": 0 - } - }, - "dst": { - "field": { - "struct": "11253655576479126322", - "field": "a" - } - } - }, - { - "src": { - "argument": { - "func": "anon_flow", - "arg": 0 - } - }, - "dst": { - "field": { - "struct": "11253655576479126323", - "field": "a" - } - } - }, - { - "src": { - "argument": { - "func": "anon_flow", - "arg": 0 - } - }, - "dst": { - "field": { - "struct": "11253655576479126324", - "field": "b" + "scopes": [ + { + "arg": -1, + "loc": 8, + "facts": [ + { + "src": { + "argument": { + "func": "anon_flow", + "arg": 0 + } + }, + "dst": { + "field": { + "struct": "11253655576479126316", + "field": "x" + } + } + }, + { + "src": { + "argument": { + "func": "anon_flow", + "arg": 0 + } + }, + "dst": { + "field": { + "struct": "11253655576479126318", + "field": "y" + } + } + }, + { + "src": { + "argument": { + "func": "anon_flow", + "arg": 0 + } + }, + "dst": { + "field": { + "struct": "11253655576479126319", + "field": "w" + } + } + }, + { + "src": { + "argument": { + "func": "anon_flow", + "arg": 0 + } + }, + "dst": { + "field": { + "struct": "11253655576479126309", + "field": "f" + } + } + }, + { + "src": { + "argument": { + "func": "anon_flow", + "arg": 0 + } + }, + "dst": { + "field": { + "struct": "11253655576479126322", + "field": "a" + } + } + }, + { + "src": { + "argument": { + "func": "anon_flow", + "arg": 0 + } + }, + "dst": { + "field": { + "struct": "11253655576479126323", + "field": "a" + } + } + }, + { + "src": { + "argument": { + "func": "anon_flow", + "arg": 0 + } + }, + "dst": { + "field": { + "struct": "11253655576479126324", + "field": "b" + } + } } - } + ] } ] } |
