Static software vulnerability detection method based on statement-level code attribute graph query
By adopting a statement-level code attribute graph query method in static detection of software vulnerabilities, the structure of the code attribute graph is simplified, the problems of complexity and inefficient performance in the existing technology are solved, and efficient and accurate vulnerability detection is achieved.
Patent Information
- Application Number
- CN202411911458.2
- Authority / Receiving Office
- CN · China
- Patent Type
- Applications(China)
- Current Assignee / Owner
- Filing Date
- 2024-12-24
- Publication Date
- 2025-04-18
AI Technical Summary
The prior art has problems such as code attribute graph (CPG) construction complexity, inefficiency in performance and high resource consumption in software vulnerability static detection, especially when dealing with large-scale software systems.
The statement-level code attribute graph query method is adopted, and by simplifying the CPG structure, combining the AST node into a single statement node, and retaining the AST details as node attributes, reducing the traversal steps of graph query and improving efficiency and performance.
It significantly optimizes the efficiency and overall performance of graph query, reduces resource consumption, and improves the response speed and accuracy of vulnerability detection in large-scale software systems.
Smart Images

Figure CN119848869A_ABST
Abstract
Description
Technical Field
[0001] The present invention provides a software vulnerability static detection method based on statement-level code attribute graph query, belonging to the technical field of information security. Background Art
[0002] In today's digital age, software vulnerabilities have become a major challenge in the field of information security. As software scale and complexity continue to grow, programmers' security knowledge reserves have become difficult to cope with increasingly complex software functions, implementation technologies, and application scenarios. The high technical threshold has not only led to a shortage of software security talents, but also made the cost of software security analysis high. Although my country has emerged with many active institutions and organizations focusing on vulnerability research and has made certain progress in vulnerability mining and management, there is still a significant gap compared with leading countries in terms of the number of 0day vulnerabilities discovered, the publication of top conference papers, the establishment and utilization of vulnerability libraries, and emergency management solutions. Therefore, my country still needs to make continuous efforts in the field of vulnerability industry to catch up with the international advanced level.
[0003] With the continuous advancement of code detection technology, researchers are increasingly inclined to use the intermediate form of graphs to represent code and conduct research through graph analysis methods. As an emerging code analysis method, graph query technology shows a higher level of abstraction and stronger expression ability than traditional detection methods. This method is expected to overcome the limitations of traditional detection technology, reveal potential vulnerabilities more comprehensively, help improve software security, and reduce the risk of information leakage and system attacks caused by vulnerabilities.
[0004] Although traditional code representation methods have certain effects, they also have many limitations. For example, the representation method based on code metrics obtains the measurement sequence of the corresponding code through several code measurement indicators, but because the code metrics are based on the overall properties of the program, they are not strongly correlated with the vulnerability code itself and have poor detection capabilities. Code metrics are summary statistics of various attributes in the entire program project. In contrast, the Token sequence is obtained by directly counting the code level. Therefore, the Token-based representation form is more correlated with vulnerabilities and has stronger detection capabilities. However, it ignores the grammatical and semantic information of the code, which limits the depth and breadth of its detection.
[0005] To overcome these limitations, researchers began to explore tree-based representations. This representation method takes into account the lexical analysis and syntax analysis of the code, taking into account both the semantics and structural information of the code, and is therefore more comprehensive than the first two representations. However, its algorithmic complexity is high, which makes it difficult to apply to practical problem solving in large-scale software systems. Nevertheless, tree-based representations have shown great potential in improving the accuracy and comprehensiveness of vulnerability detection.
[0006] In contrast, graph-based representations have significant advantages in terms of comprehensiveness in semantics. Graph representations can not only capture the structural information of the code, but also better represent the complex relationships and dependencies in the code. Through graph analysis methods, researchers can gain a deeper understanding of the dynamic behavior and potential vulnerabilities of the code. In addition, when dealing with large-scale software systems, graph representations can reduce the complexity of algorithms through the efficiency and scalability of graph algorithms, making them more suitable for practical application scenarios. In this representation, source code is converted into a graph structure, in which nodes can represent program elements such as variables, functions, and classes, while edges represent various relationships between these elements, such as function calls, variable access, or inheritance relationships. This graph-based representation method makes complex program relationships more intuitive and easy to analyze. For example, potential error patterns can be identified by analyzing the paths in the graph.
[0007] Joern's technical implementation solution revolves around the generation and query of code property graphs (CPGs), providing an efficient foundation for static analysis and vulnerability detection. Its core lies in the unified representation of the structure and semantics of the source code as a multi-dimensional graph structure to support the analysis of complex code. The code property graph combines models such as the abstract syntax tree (AST), control flow graph (CFG), and program dependency graph (PDG), integrating the grammatical structure, execution path, and dependency relationship in the source code into a single graph.
[0008] First, Joern starts with source code parsing, and generates an abstract syntax tree (AST) through syntax analysis to capture the grammatical structure and language characteristics of the program. The result of this stage is a tree structure represented by nodes and edges. The nodes correspond to the syntax elements in the code (such as variables, functions, expressions, etc.), and the edges represent the nesting or subordinate relationship between syntax elements. Based on the AST, Joern constructs a control flow graph (CFG) to show the execution paths and conditional branches of different codes in the program. Furthermore, Joern introduces data dependency and control dependency information through the program dependency graph (PDG) to capture the definition and usage relationship of variables, as well as the impact of conditions and loops on program behavior.
[0009] After completing the generation of CPG, Joern stores it as a graph database to lay the foundation for subsequent analysis. Joern uses efficient graph databases (such as Neo4j) and uses its graphical storage and query capabilities to quickly perform query and pattern matching operations.
[0010] In-depth research revealed that Joern has some significant shortcomings in practical applications.
[0011] First, Joern uses the abstract syntax tree (AST) as the basic unit of the node. Although its fine-grained design helps capture the precise structure of the code, as the code size increases, the storage space requirements will increase dramatically. In addition, since Joern's AST level decomposes statements, it becomes difficult to obtain source code information directly from the graph. In general, in vulnerability detection scenarios, too fine granularity does not show obvious practical advantages, but may increase computational burden and complexity.
[0012] Secondly, in the design of edges, Joern used the program dependency graph (PDG) to express node relationships by combining control dependency and data dependency. However, the control flow graph (CFG) itself can already express control dependency. This redundant design increases the complexity of the edge hierarchy, further affecting performance and scalability.
[0013] Although Joern has achieved certain results in areas such as static analysis and vulnerability detection, it still faces some challenges that need to be solved in practical applications. One notable problem is the construction of complex code property graphs (CPGs). Joern builds CPGs at the abstract syntax tree (AST) level, which makes the generated graphs become extremely large as the size of the code base continues to expand. As the complexity of the graph increases, the analysis performance is often significantly affected, and the analysis process may become slower and less efficient. At the same time, large CPGs also consume more memory resources, which is particularly prominent when dealing with large code bases. Therefore, how to optimize the construction and management of CPGs and improve their processing capabilities has become a key problem that Joern needs to overcome in practical applications. Summary of the invention
[0014] The present invention implements a software vulnerability static detection method based on statement-level code property graph query, which is designed for vulnerability detection based on graph query analysis and is particularly suitable for security analysis of large software systems. Its goal is to provide a complete analysis process from code property graph (CPG) extraction to graph query execution, providing efficient and reliable support for vulnerability detection. Its main components include: CPG extraction module and query engine for executing vulnerability query.
[0015] In order to effectively cope with the challenges brought by the complexity of the traditional CPG structure, the present invention proposes a simplified CPG structure. The simplified structure optimizes performance by retaining necessary key information and significantly reducing the size of the graph. Specifically, traditional CPGs usually include a large number of abstract syntax tree (AST) nodes, and in the new simplified structure, these AST nodes are merged into a single statement node, while the detailed information of the AST is retained as node attributes. This design effectively reduces the traversal steps required for graph query, thereby significantly improving the efficiency and overall performance of graph query, so that a high response speed can be maintained when facing large-scale software systems.
[0016] In order to further improve the accuracy of vulnerability detection, the present invention also proposes three algorithms specifically for statement-level detection, which can give full play to the advantages of graph query in vulnerability detection. Unlike traditional detection methods based on function level or control flow graph, statement-level detection can more accurately capture the details of potential vulnerabilities and reduce false positives and missed reports. The three algorithms use different detection strategies to accurately locate code snippets that may have vulnerabilities when executing queries.
[0017] The specific technical solution is:
[0018] A software vulnerability static detection method based on statement-level code attribute graph query; including graph database construction storage and graph query process.
[0019] S1. In the process of building storage, we mainly focus on analyzing project files and converting them into graph structure storage. This process includes the following key steps:
[0020] S1.1. Graph construction:
[0021] First, the project files to be analyzed are identified according to the configuration file and necessary preprocessing operations are performed, followed by in-depth source code analysis and graph information extraction. This information is then encapsulated into nodes and edges, and finally maintained into a graphical information structure.
[0022] S1.2, Graph Storage:
[0023] The serialized key information will be efficiently stored in the database.
[0024] S2. During the query process, the information stored in the database is used to respond to various query requirements. If we explore this process in detail, we can divide it into the following three detailed steps:
[0025] S2.1. Code graph deserialization:
[0026] A code graph is a graph data structure used to represent various entities and their interrelationships in source code. During the deserialization phase, the serialized forms of these graphs are extracted from the database and converted back into an in-memory graph structure.
[0027] S2.2. Traversal operations on the graph:
[0028] The code graph is loaded into memory and traversal operations on the graph are performed according to predefined rules, including searching for nodes of a specific type and traversing the edges between nodes.
[0029] S2.3, core query algorithm implementation:
[0030] By further encapsulating the traversal operations on the graph, a statement-level detection algorithm is constructed. The algorithm is mainly divided into two categories: single statement detection and inter-statement relationship detection, which respectively deal with the logic problems of a single statement and the correlation problems between multiple statements.
[0031] (1) Construction of graph points
[0032] When constructing the points on the graph, the granularity unit is the statement. The internal AST structure that constitutes the statement information is not explicitly maintained on the graph, but the information is extracted and stored on the points in the form of JSON serialized strings to reduce the maintenance cost of the graph.
[0033] (2) Construction of control flow edges in the graph
[0034] CFG is a graphical representation of the program control flow, showing all possible execution paths in the program in a graphical way. The direction of the CFG edge follows the execution order of the code.
[0035] (3) Data flow edge construction in the graph
[0036] DFG is a graphical structure that represents the data flow of a program. It focuses on the flow and operation of data in a program. It traces back from the point where the data is used to its point of definition in order to perform tracing operations.
[0037] (4) Function call edge construction in the graph
[0038] CG is used to represent the function call relationship in a program. If a function calls another function, the execution order of the code will change, and the execution will be transferred from the calling point to the inside of the called function, and a CG edge will be established from the calling point to the called function. At the same time, when the called function is executed, the function end node of the called function will generate a return edge pointing to the calling node for the execution of subsequent statements.
[0039] (5) Graph Storage
[0040] Specifically, the content stored in the database is designed based on the key content extracted from the above analysis content;
[0041] (6) Deserialization implementation
[0042] After the code analysis is completed, the code is converted into an intermediate representation of the graph, where each code statement corresponds to a specific node. The key information of the code will be stored in the form of JSON fields, and different types of statements are accurately extracted according to the structure of AST, so that the structure and semantics of the code can be effectively represented in the database.
[0043] (7) Traversal function implementation
[0044] Gremlin is used to obtain the vertices and edges in the graph. After obtaining the vertices and edges, the graph traversal algorithm is manually simulated;
[0045] (8) Core detection algorithm
[0046] Query implementations are divided into two types. The first type involves statements that have problems on their own, independent of other statements and not related to the flow of data or other parts of the program. The second type is Path-Problem, which identifies specific statements as potential sensitive sources and sensitive sinks.
[0047] For the first case, use FilterPredicate to filter all nodes.
[0048] For the second case, use FilterPredicate to filter out suspicious sources and sinks, and then use FlowPredicate to traverse the graph for verification to obtain more accurate results.
[0049] The present invention is to deeply optimize the traditional code property graph (CPG) to improve the efficiency and accuracy of vulnerability detection. Specifically, the present invention reduces the granularity of the nodes in the graph and refines the nodes at the traditional abstract syntax tree (AST) level to the statement level, thereby effectively simplifying the structure of the graph and reducing unnecessary complexity. This improvement significantly reduces the size of the CPG when processing large-scale code bases, greatly improves the processing efficiency of graph queries, and reduces the system's resource consumption in storage and computing.
[0050] In addition to optimizing the node granularity, the present invention also streamlines the edges in the graph, removing many redundant relationships and irrelevant connections, thereby further optimizing the graph structure. Through this streamlined edge design, the complexity of the graph is controlled, and the query engine can traverse and execute graph queries more efficiently, avoiding the performance bottleneck caused by redundant edges in traditional methods. In addition, the optimized graph structure also improves storage and processing efficiency, making the system more stable and efficient when processing large software projects.
[0051] Based on this simplified code property graph, the present invention also designs efficient vulnerability detection algorithms, which make full use of the simplified graph structure and can quickly and accurately detect potential vulnerabilities. By closely combining graph query with vulnerability detection, the algorithm of the present invention can efficiently perform complex query operations, and improve the accuracy and sensitivity of vulnerability detection through precise statement-level analysis. Compared with traditional vulnerability detection methods, these algorithms can not only reduce false positives and false negatives, but also more accurately capture security risks in complex codes. BRIEF DESCRIPTION OF THE DRAWINGS
[0052] Figure 1 This is a system architecture diagram of the present invention;
[0053] Figure 2 is a CFG example diagram of an embodiment;
[0054] Figure 3 This is a CG example diagram of the embodiment. DETAILED DESCRIPTION
[0055] The workflow diagram of the software vulnerability static detection method based on statement-level code attribute graph query of the present invention is as follows: Figure 1 shown.
[0056] The overall process can be divided into two main stages: graph database construction storage and graph query process.
[0057] S1. In the process of building storage, we mainly focus on analyzing project files and converting them into graph structure storage. This process includes the following key steps:
[0058] S1.1. Graph construction:
[0059] First, the project files to be analyzed are identified according to the configuration file and necessary preprocessing operations are performed, followed by in-depth source code analysis and graph information extraction. This information is then encapsulated into nodes and edges, and finally maintained into a graphical information structure.
[0060] S1.2, Graph Storage:
[0061] The key information after serialization will be efficiently stored in the database. This step not only ensures the persistence of data, but also facilitates efficient data retrieval in subsequent query and analysis processes.
[0062] S2. In the query process, the main goal is to effectively use the information stored in the database to respond to various query requirements. Exploring this process in detail, it can be divided into the following three detailed steps:
[0063] S2.1. Code graph deserialization:
[0064] A code graph is a graph data structure used to represent various entities (such as functions, variables, etc.) and their relationships in the source code. In the deserialization phase, the serialized form of these graphs is extracted from the database and converted back to an in-memory graph structure. This step is necessary because it enables subsequent graph traversal and analysis operations to be performed directly in memory, thereby increasing processing speed.
[0065] S2.2. Traversal operations on the graph:
[0066] Once the code graph is loaded into memory, traversal operations on the graph can be performed according to predefined rules. This includes searching for nodes of a specific type, traversing the edges between nodes, etc. The complexity and scope of these operations depend on the user's query requirements, and may involve simple searches to complex graph structure analysis.
[0067] S2.3, core query algorithm implementation:
[0068] By further encapsulating the traversal operations on the graph, a statement-level detection algorithm can be constructed. The algorithm is mainly divided into two categories: single statement detection and statement relationship detection, which respectively deal with the logic problems of a single statement and the correlation problems between multiple statements. According to different detection requirements, special algorithms are designed to facilitate efficient query and analysis, thereby improving the accuracy and flexibility of detection.
[0069] (1) Construction of graph points
[0070] When constructing the points on the graph, the granularity unit is the statement. The internal AST structure that constitutes the statement information is not explicitly maintained on the graph, but the information is extracted and stored on the points in the form of JSON serialized strings to reduce the maintenance cost of the graph.
[0071] For example, considering that the grammatical rules of programming languages usually follow context-free grammars, the grammatical structure of the if statement can clearly reflect this. When serializing information for storage, the data storage order that follows the grammar actually represents the logical order of the nodes in the graph. Specifically, the grammatical structure of the if statement is as follows:
[0072] <if_statement>::=if( <condition> ) <statement>
[0073] <condition> ::= <expression><comparison_operator> <expression>
[0074] <comparison_operator> ::=<|>|<=|>=|==|!=
[0075] The if statement is constructed as a condition part. Through the serialization order from left to right inside the condition, the internal structure of the statement is still preserved, and the complexity of the graph is also reduced.
[0076] Specifically in C / C++ language, statements are one of the basic units that make up a program, used to express certain operations or control logic. Statements can be roughly classified into the types shown in Table 1, and each type has its own specific syntax and purpose. After completing the detailed division of statements, the internal information of the statements can be accurately extracted, and the content can be extracted for each type of statement and the expression in each type of statement.
[0077] Table 1 Overview of actual statement types
[0078]
[0079]
[0080] (2) Construction of control flow edges in the graph
[0081] CFG is a graphical representation of program control flow, which shows all possible execution paths in the program in a graphical way. In the project, the direction of CFG edges follows the execution order of the code. After converting the sample code to CFG, it can be represented as follows Figure 2 The CFG diagram shown.
[0082] CFG edges can be divided into three categories, which are briefly described as follows:
[0083] A.True: Jump if the condition is true. Display the annotation in the figure
[0084] B.False: The condition is judged as a false jump. Display the label in the figure
[0085] C.Empty: Perform an unconditional jump based on the context execution relationship. Implicitly expressed in the diagram
[0086] In the construction of CFG, most statements will follow the above logic and jump accordingly according to the situation. However, some statements have the functions of unconditional jump and unconditional end, so special judgment is required:
[0087] a)Continue: Depends on the most recent loop statement
[0088] b)Break: Depends on the most recent loop statement
[0089] c) Goto: Depends on the goto label
[0090] d)Return
[0091] The CFG in a function is based on statements. For each statement, most statements have the characteristics of a single entry and a single exit. For the case of a compound statement {}, a recursive construction will be performed deep inside {}.
[0092] (3) Data flow edge construction in the graph
[0093] DFG is a graphical structure that represents the data flow of a program. It focuses on the flow and operation of data in a program. Compared with traditional DFG, the direction in the project is the opposite, that is, tracing back from the point where the data is used to its point of definition in order to perform tracing operations.
[0094] (3.1) DFG within a function
[0095] In the DFG of the project, it is generally constructed according to the def-use edge. Def-use refers to the relationship between the definition of a variable and its use. In other words, the def-use edge shows how a variable is used after it is defined during program execution. Specifically, since each statement may reference other variables or redefine a variable, for the former case, that is, the use of the variable, it is necessary to look up for the def operation closest to it; for the latter case, that is, the def of the variable.
[0096] In the project scenario, there are the following def situations. Except for the following situations, the remaining operations are use operations:
[0097] A. The variable is assigned on the left side
[0098] B. Variables perform self-operations such as self-increment and self-decrement
[0099] C. The variable is a pointer type and is used as a function parameter
[0100] D. The variable is a normal variable and is used as a function parameter after being operated by &
[0101] The def-use edge also has its flaws. Each time a variable is redefined, the previous def-use edge is disconnected and a new def-use edge is established. This is because the reassignment of a variable actually modifies the definition of the variable, which makes the previous definition invalid and establishes a new def-use relationship.
[0102] int a;
[0103] a=0;
[0104] a=1;
[0105] In the above code, variable a is first defined as 0 and then reassigned to 1. After each reassignment, the original def-use relationship is broken and a new def-use relationship is established. This means that after the second assignment, the def-use relationship associated with variable a will be independent of the relationship established during the first assignment.
[0106] Therefore, to address the above problems, the traditional DFG is redesigned. First, the variable definition is regarded as a reference variable, and a def-use structure is established. Secondly, the variable declaration position is added as the starting point, and each use of the variable is used as the end point to establish an edge from declaration to use. That is, in the above code, `int a;` will point to `a=0;` and `a=1;`.
[0107] (3.2) DFG between functions
[0108] If a statement in a function calls another function, a DFG relationship may be formed between the functions. The input edge of the DFG can be preliminarily processed by the existence of the parameters. If the called function has parameters, the function parameters have data dependencies on the actual parameters. A DFG edge can be added from the call point to the function declaration (function definition in another file) or function definition (function definition in this file) to indicate the flow of parameters.
[0109] The DFG outbound edge situation of the called function is more complicated, and the following classification discussion is carried out:
[0110] (a) A pointer type parameter is used directly as a function parameter or is on the left side of an assignment binary operation. From a conservative perspective, this variable has the risk of being modified, and DFG edges need to be established for all reachable return statements.
[0111] (b) Pointer type parameters are indirectly used as function parameters or are on the left side of binary assignment operations. This situation can mostly be regarded as the parameter being assigned to a local variable in the function, also known as an alias, and the modification of the local variable will actually affect the parameter. Therefore, from a conservative perspective, it is necessary to establish DFG edges for all reachable return statements.
[0112] From the discussion of the DFG outgoing edges of the called function, we can see that within the function, we need to focus on function calls with pointer type parameters and statements where the left value of a binary assignment expression is a function call. Both of these situations require the establishment of DFG edges to all reachable return statements. Since the return statement is followed by a virtual function end node, in order to simplify the operation, the DFG edge can be directly established to the function end node without having to establish it to the return statement through reachability.
[0113] (4) Function call edge construction in the graph
[0114] like Figure 3 CG is used to represent the function call relationship in a program. If a function calls another function, the execution order of the code will change, and the execution will be transferred from the calling point to the inside of the called function. Therefore, a CG edge can be established from the calling point to the called function. At the same time, when the called function is executed, the function end node of the called function will generate a return edge pointing to the calling node for the execution of subsequent statements.
[0115] (5) Graph Storage
[0116] Specifically, the key contents extracted from the above analysis are designed to be stored in the database as shown in Tables 2 to 5.
[0117] Table 2 Design table of map database points
[0118]
[0119] Table 3 Graph database CFG edge design table
[0120]
[0121] Table 4 DFG edge design table of graph database
[0122]
[0123]
[0124] Table 5 CG edge design table of graph database
[0125]
[0126] (6) Deserialization implementation
[0127] After the code analysis is completed, the code is converted into an intermediate representation of the graph, where each code statement corresponds to a specific node. The key information of the code will be stored in the form of JSON fields, and different types of statements are accurately extracted according to the structure of AST, so that the structure and semantics of the code can be effectively represented in the database.
[0128] Since different statements have different information, the processing methods are also different and relatively independent. Therefore, the factory mode can be used for deserialization. Specifically, each type of statement will have a corresponding factory to build it. This is achieved by adding the _type field in the node's JSON data.
[0129] The following uses expression statements as an example to explain how to construct JSON attributes.
[0130] In many scenarios, the expression will present a recursive structure. For example, binary expressions and ID expressions can be nested in binary expressions. Therefore, the JSON structure of the expression needs to be analyzed according to the recursive structure as a whole.
[0131] The overall idea of binary expression serialization is given below:
[0132] A. Identify the node type according to the _type field;
[0133] B. Identify the operation type of the current calculation according to the basicType field;
[0134] C. Identify the binary operator according to the operator field;
[0135] D. Through recursive construction, the left operand of the binary operation is identified according to the leftOp field;
[0136] E. Through recursive construction, the right operand of the binary operation is identified according to the rightOp field;
[0137] The pseudo code for the above statement is shown in Table 6:
[0138] Table 6 Binary operation serialization construction algorithm
[0139]
[0140]
[0141] Accordingly, in the query engine, a corresponding deserialization method needs to be constructed to restore the above JSON nodes to facilitate subsequent analysis.
[0142] (7) Traversal function implementation
[0143] Although Gremlin provides a complete set of built-in graph traversal operations, in order to deeply explore the AstNode information contained in each node in the graph and maximize the use of this data, Gremlin's standard graph traversal method is not used. Specifically, Gremlin is used to obtain the vertices and edges in the graph, but in the graph traversal process, it does not rely on Gremlin's existing traversal library. After obtaining the points and edges, a more in-depth analysis of the node data can be achieved by manually simulating the graph traversal algorithm. This method can more effectively utilize the information in the graph structure.
[0144] As for suspicious nodes, a sophisticated screening strategy is required. In combination with language features, a predicate-based design is adopted to effectively screen nodes during traversal. Java 8 introduced the Predicate interface, as shown in the following code, which is used to represent a predicate (Boolean expression) of a parameter. The Predicate interface defines an abstract method test(T t), which receives a parameter of type generic T and returns a Boolean value. If the parameter meets the conditions defined by the predicate, true is returned; otherwise, false is returned.
[0145]
[0146] Therefore, in terms of node traversal, the node screening function can be achieved by customizing Predicate. The currently implemented underlying functions are shown in Table 7:
[0147] Table 7 Design of traversal function
[0148]
[0149] After implementing the above two operations, you can combine the two, use FilterPredicate to obtain the set of initial points, and make FlowPredicate for each node in the set. However, before traversal, you need to implement various traversal strategies. As discussed in the requirements analysis section, all kinds of traversal operations rely on the use of DFS at the bottom, and different strategies are only distinguished by the number of traversals and the total type of edge traversal. Summarize the types of existing edges and various CWEs, and dig out the traversal operations shown in Table 8 for use.
[0150] Table 8 Design of traversal strategy
[0151]
[0152] (8) Core detection algorithm
[0153] (8.1) Basic testing
[0154] Query implementations can be roughly divided into two types. The first type involves statements that have problems on their own, independent of other statements and not related to the flow of data or other parts of the program. The second type is Path-Problem, which identifies specific statements as potential sensitive sources and sensitive sinks. In this analysis, the program may exhibit security vulnerabilities or other problems only when data flows from the source to the sink point.
[0155] For the first case, use FilterPredicate to filter all nodes.
[0156] For the second case, use FilterPredicate to filter out suspicious sources and sinks, and then use FlowPredicate to traverse the graph for verification to obtain more accurate results.
[0157] According to different actual situations, all special situations are listed as follows, please refer to Table 9:
[0158] Table 9 Query logic overview
[0159]
[0160]
[0161] (8.2) Back-propagation detection
[0162] TaintFlow's operations can already handle most scenarios, but in some scenarios, you can actively encapsulate statements into functions to erase some data flows that should exist, as shown in the following code:
[0163]
[0164] In this case, since the data connection is cut off, the above-mentioned TaintFlow loses its detection ability. Fortunately, this type of problem has obvious characteristics. The scope of the operated variable needs to be larger than the local scope in the function, that is, it needs to reach the global scope. Therefore, the detection method shown in Table 10 is designed for this situation.
[0165] Table 10 Back propagation detection design
[0166]
[0167]
[0168] (8.3) Improve detection accuracy
[0169] TaintFlow and CrossFunctionTainFlow are already able to complete the task of detecting at the statement level, but in order to improve the accuracy of detection, the AST level content still needs to be considered. The following example illustrates the situation where the above detection capabilities are insufficient:
[0170]
[0171] The above comparison example can well show that if we only rely on the edges between statements without considering the attributes of the edges, DFG will have the risk of misjudgment. The reason is that multiple variables may be modified in one statement, and the difference between the DFG edges derived from different variables lies in the different attributes on the edges. Therefore, the design of the flow shown in Table 11 is derived:
[0172] Table 11 Algorithms for improving detection accuracy
[0173]
[0174] In the present invention, Eclipse CDT (C / C++ Development Tooling) is used as a parser for parsing C / C++ codes. Eclipse CDT is a mature and widely used development tool that provides powerful C / C++ parsing and analysis functions, and can efficiently handle syntax analysis, abstract syntax tree (AST) generation and other static analysis tasks of C / C++ source code. In contrast, there are other parsers on the market, such as the front end of Clang or GCC.
[0175] For the implementation of Predicate, the present invention uses the language characteristics of Java for development. Java language, due to its concise syntax, cross-platform characteristics and powerful library support, makes the implementation of Predicate efficient and easy to maintain. In Java, Predicate is usually used to process Boolean logic and conditional expressions, and can provide flexible conditional judgment in graph query and vulnerability detection. However, as an alternative, it is also possible to consider using scripting languages such as Python, which have certain advantages in rapid development and dynamic characteristics.< / expression> < / expression> < / condition> < / statement> < / condition>
Claims
1. A software vulnerability static detection method based on statement-level code attribute graph query, characterized in that: Including graph database construction storage and graph query process; S1. In the process of building storage, we are committed to analyzing engineering files and converting them into graph structure storage; S2. During the query process, the information stored in the database is used to respond to various query requirements.
2. According to claim 1, a software vulnerability static detection method based on statement-level code attribute graph query is characterized in that: S1 includes the following steps: S1.
1. Graph construction: First, the project files to be analyzed are identified according to the configuration file and necessary preprocessing operations are performed. Then, in-depth source code analysis is performed to extract graph information. This information is then encapsulated into nodes and edges, and finally maintained into a graphical information structure. S1.2, Graph Storage: The serialized key information will be efficiently stored in the database.
3. According to claim 1, a software vulnerability static detection method based on statement-level code attribute graph query is characterized in that: S2 includes the following steps: S2.
1. Code graph deserialization: A code graph is a graph data structure used to represent various entities and their interrelationships in source code. In the deserialization phase, the serialized forms of these graphs are extracted from the database and converted back into an in-memory graph structure. S2.
2. Traversal operations on the graph: The code graph is loaded into memory and traversal operations on the graph are performed according to predefined rules, including searching for nodes of a specific type and traversing the edges between nodes. S2.3, core query algorithm implementation: By further encapsulating the traversal operations on the graph, a statement-level detection algorithm is constructed; the algorithm is mainly divided into two categories: single statement detection and inter-statement relationship detection, which respectively deal with the logical problems of a single statement and the correlation problems between multiple statements.
4. According to claim 3, a software vulnerability static detection method based on statement-level code attribute graph query is characterized in that: S2.3 specifically includes: (1) Construction of graph points When constructing points on the graph, statements are used as the granularity unit. The internal AST structure that constitutes the statement information is not explicitly maintained on the graph, but the information is extracted and stored on the points in the form of JSON serialized strings to reduce the maintenance cost of the graph. (2) Construction of control flow edges in the graph CFG is a graphical representation of the program control flow, which shows all possible execution paths in the program in a graphical way; the direction of the CFG edge follows the execution order of the code; (3) Data flow edge construction in the graph DFG is a graphical structure that represents the data flow of a program. It focuses on the flow and operation of data in a program. It traces the data from its usage point to its definition point in order to perform tracing operations. (4) Function call edge construction in the graph CG is used to represent the function call relationship in a program. If another function is called from within a function, the execution order of the code will change, and the execution will be transferred from the calling point to the inside of the called function. A CG edge will be established from the calling point to the called function. At the same time, when the called function is executed, the function end node of the called function will generate a return edge pointing to the calling node for the execution of subsequent statements. (5) Graph Storage Design the storage content in the database based on the key content extracted from the above analysis; (6) Deserialization implementation After the code analysis is completed, the code is converted into an intermediate representation of the graph, where each code statement corresponds to a specific node; the key information of the code is stored in the form of JSON fields, and different types of statements are accurately extracted according to the structure of AST, so that the structure and semantics of the code can be effectively represented in the database; (7) Traversal function implementation Gremlin is used to obtain the vertices and edges in the graph. After obtaining the vertices and edges, the graph traversal algorithm is manually simulated; (8) Core detection algorithm Query implementations are divided into two types; the first type involves statements that have problems in themselves, which are independent of other statements and do not involve the flow of data or other parts of the program; the second type is Path-Problem, which identifies specific statements as potential sensitive sources and sensitive sinks; For the first case, use FilterPredicate to filter all nodes; For the second case, use FilterPredicate to filter out suspicious sources and sinks, and then use FlowPredicate to traverse the graph for verification to obtain more accurate results.
Citation Information
Patent Citations
Software logic vulnerability detection method based on graph mining
CN111931181A