codeql-development-mcp-server 2.24.3 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codeql-development-mcp-server.js +48111 -49526
- package/dist/codeql-development-mcp-server.js.map +4 -4
- package/package.json +9 -9
- package/ql/actions/tools/src/PrintCFG/PrintCFG.ql +1 -3
- package/ql/actions/tools/src/codeql-pack.lock.yml +14 -14
- package/ql/actions/tools/src/codeql-pack.yml +2 -2
- package/ql/cpp/tools/src/CallGraphFrom/CallGraphFrom.ql +6 -20
- package/ql/cpp/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/cpp/tools/src/CallGraphFromTo/CallGraphFromTo.ql +77 -0
- package/ql/cpp/tools/src/CallGraphTo/CallGraphTo.ql +6 -20
- package/ql/cpp/tools/src/ExternalPredicates.qll +14 -0
- package/ql/cpp/tools/src/PrintAST/PrintAST.ql +9 -20
- package/ql/cpp/tools/src/PrintCFG/PrintCFG.ql +1 -3
- package/ql/cpp/tools/src/codeql-pack.lock.yml +12 -12
- package/ql/cpp/tools/src/codeql-pack.yml +2 -2
- package/ql/csharp/tools/src/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/csharp/tools/src/CallGraphFromTo/CallGraphFromTo.md +49 -0
- package/ql/csharp/tools/src/CallGraphFromTo/CallGraphFromTo.ql +64 -0
- package/ql/csharp/tools/src/CallGraphTo/CallGraphTo.ql +4 -19
- package/ql/csharp/tools/src/ExternalPredicates.qll +14 -0
- package/ql/csharp/tools/src/PrintAST/PrintAST.ql +9 -17
- package/ql/csharp/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/csharp/tools/src/codeql-pack.yml +2 -2
- package/ql/go/tools/src/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/go/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/go/tools/src/CallGraphFromTo/CallGraphFromTo.ql +53 -0
- package/ql/go/tools/src/CallGraphTo/CallGraphTo.ql +4 -20
- package/ql/go/tools/src/ExternalPredicates.qll +14 -0
- package/ql/go/tools/src/PrintAST/PrintAST.ql +132 -22
- package/ql/go/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/go/tools/src/codeql-pack.yml +2 -2
- package/ql/java/tools/src/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/java/tools/src/CallGraphFromTo/CallGraphFromTo.md +49 -0
- package/ql/java/tools/src/CallGraphFromTo/CallGraphFromTo.ql +64 -0
- package/ql/java/tools/src/CallGraphTo/CallGraphTo.ql +4 -19
- package/ql/java/tools/src/ExternalPredicates.qll +14 -0
- package/ql/java/tools/src/PrintAST/PrintAST.ql +9 -17
- package/ql/java/tools/src/PrintCFG/PrintCFG.ql +11 -10
- package/ql/java/tools/src/codeql-pack.lock.yml +14 -14
- package/ql/java/tools/src/codeql-pack.yml +2 -2
- package/ql/javascript/tools/src/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/javascript/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/javascript/tools/src/CallGraphFromTo/CallGraphFromTo.ql +69 -0
- package/ql/javascript/tools/src/CallGraphTo/CallGraphTo.ql +4 -20
- package/ql/javascript/tools/src/ExternalPredicates.qll +14 -0
- package/ql/javascript/tools/src/PrintAST/PrintAST.ql +9 -20
- package/ql/javascript/tools/src/PrintCFG/PrintCFG.ql +1 -3
- package/ql/javascript/tools/src/codeql-pack.lock.yml +13 -13
- package/ql/javascript/tools/src/codeql-pack.yml +2 -2
- package/ql/python/tools/src/CallGraphFrom/CallGraphFrom.ql +3 -17
- package/ql/python/tools/src/CallGraphFromTo/CallGraphFromTo.md +46 -0
- package/ql/python/tools/src/CallGraphFromTo/CallGraphFromTo.ql +71 -0
- package/ql/python/tools/src/CallGraphTo/CallGraphTo.ql +6 -22
- package/ql/python/tools/src/ExternalPredicates.qll +14 -0
- package/ql/python/tools/src/PrintAST/PrintAST.ql +9 -20
- package/ql/python/tools/src/PrintCFG/PrintCFG.ql +1 -3
- package/ql/python/tools/src/codeql-pack.lock.yml +13 -13
- package/ql/python/tools/src/codeql-pack.yml +2 -2
- package/ql/ruby/tools/src/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/ruby/tools/src/CallGraphFromTo/CallGraphFromTo.md +48 -0
- package/ql/ruby/tools/src/CallGraphFromTo/CallGraphFromTo.ql +50 -0
- package/ql/ruby/tools/src/CallGraphTo/CallGraphTo.ql +4 -20
- package/ql/ruby/tools/src/ExternalPredicates.qll +14 -0
- package/ql/ruby/tools/src/PrintAST/PrintAST.ql +9 -17
- package/ql/ruby/tools/src/PrintCFG/PrintCFG.ql +1 -3
- package/ql/ruby/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/ruby/tools/src/codeql-pack.yml +2 -2
- package/ql/swift/tools/src/CallGraphFrom/CallGraphFrom.ql +7 -16
- package/ql/swift/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/swift/tools/src/CallGraphFromTo/CallGraphFromTo.ql +80 -0
- package/ql/swift/tools/src/CallGraphTo/CallGraphTo.ql +8 -14
- package/ql/swift/tools/src/ExternalPredicates.qll +14 -0
- package/ql/swift/tools/src/PrintAST/PrintAST.ql +5 -15
- package/ql/swift/tools/src/PrintCFG/PrintCFG.ql +5 -15
- package/ql/swift/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/swift/tools/src/codeql-pack.yml +2 -2
|
@@ -8,18 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
import csharp
|
|
10
10
|
import semmle.code.csharp.PrintAst
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the source files to generate AST from.
|
|
14
|
-
* Can be a single file path or comma-separated list of file paths.
|
|
15
|
-
*/
|
|
16
|
-
external string selectedSourceFiles();
|
|
11
|
+
import ExternalPredicates
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Gets a single source file from the comma-separated list.
|
|
20
15
|
*/
|
|
21
16
|
string getSelectedSourceFile() {
|
|
22
|
-
|
|
17
|
+
exists(string s | selectedSourceFiles(s) | result = s.splitAt(",").trim())
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
/**
|
|
@@ -30,11 +25,14 @@ File getSelectedFile() {
|
|
|
30
25
|
selectedFile = getSelectedSourceFile() and
|
|
31
26
|
(
|
|
32
27
|
// Match by exact relative path from source root
|
|
33
|
-
result.getRelativePath() = selectedFile
|
|
28
|
+
result.getRelativePath() = selectedFile
|
|
29
|
+
or
|
|
34
30
|
// Match by file name if no path separators
|
|
35
|
-
|
|
31
|
+
not selectedFile.matches("%/%") and result.getBaseName() = selectedFile
|
|
32
|
+
or
|
|
36
33
|
// Match by ending path component
|
|
37
|
-
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
34
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
35
|
+
selectedFile
|
|
38
36
|
)
|
|
39
37
|
)
|
|
40
38
|
}
|
|
@@ -46,12 +44,6 @@ File getSelectedFile() {
|
|
|
46
44
|
class Cfg extends PrintAstConfiguration {
|
|
47
45
|
override predicate shouldPrint(Element e, Location l) {
|
|
48
46
|
super.shouldPrint(e, l) and
|
|
49
|
-
(
|
|
50
|
-
// Use external predicate if available
|
|
51
|
-
l.getFile() = getSelectedFile()
|
|
52
|
-
or
|
|
53
|
-
// Fallback for unit tests: include all files
|
|
54
|
-
not exists(getSelectedFile())
|
|
55
|
-
)
|
|
47
|
+
l.getFile() = getSelectedFile()
|
|
56
48
|
}
|
|
57
49
|
}
|
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
lockVersion: 1.0.0
|
|
3
3
|
dependencies:
|
|
4
4
|
codeql/controlflow:
|
|
5
|
-
version: 2.0.
|
|
5
|
+
version: 2.0.28
|
|
6
6
|
codeql/csharp-all:
|
|
7
|
-
version: 5.4.
|
|
7
|
+
version: 5.4.9
|
|
8
8
|
codeql/dataflow:
|
|
9
|
-
version: 2.0
|
|
9
|
+
version: 2.1.0
|
|
10
10
|
codeql/mad:
|
|
11
|
-
version: 1.0.
|
|
11
|
+
version: 1.0.44
|
|
12
12
|
codeql/ssa:
|
|
13
|
-
version: 2.0.
|
|
13
|
+
version: 2.0.20
|
|
14
14
|
codeql/threat-models:
|
|
15
|
-
version: 1.0.
|
|
15
|
+
version: 1.0.44
|
|
16
16
|
codeql/tutorial:
|
|
17
|
-
version: 1.0.
|
|
17
|
+
version: 1.0.44
|
|
18
18
|
codeql/typetracking:
|
|
19
|
-
version: 2.0.25
|
|
20
|
-
codeql/util:
|
|
21
19
|
version: 2.0.28
|
|
20
|
+
codeql/util:
|
|
21
|
+
version: 2.0.31
|
|
22
22
|
codeql/xml:
|
|
23
|
-
version: 1.0.
|
|
23
|
+
version: 1.0.44
|
|
24
24
|
compiled: false
|
|
@@ -8,32 +8,17 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import go
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the source function name for which to generate the call graph.
|
|
14
|
-
* Can be a single function name or comma-separated list of function names.
|
|
15
|
-
*/
|
|
16
|
-
external string sourceFunction();
|
|
11
|
+
import ExternalPredicates
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Gets a single source function name from the comma-separated list.
|
|
20
15
|
*/
|
|
21
16
|
string getSourceFunctionName() {
|
|
22
|
-
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
from CallExpr call, FuncDecl source
|
|
26
21
|
where
|
|
27
22
|
call.getEnclosingFunction() = source and
|
|
28
|
-
(
|
|
29
|
-
|
|
30
|
-
source.getName() = getSourceFunctionName()
|
|
31
|
-
or
|
|
32
|
-
// Fallback for unit tests: include test files
|
|
33
|
-
(
|
|
34
|
-
not exists(getSourceFunctionName()) and
|
|
35
|
-
source.getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
36
|
-
)
|
|
37
|
-
)
|
|
38
|
-
select call,
|
|
39
|
-
"Call from `" + source.getName() + "` to `" + call.getTarget().getName() + "`"
|
|
23
|
+
source.getName() = getSourceFunctionName()
|
|
24
|
+
select call, "Call from `" + source.getName() + "` to `" + call.getTarget().getName() + "`"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# CallGraphFromTo for Go
|
|
2
|
+
|
|
3
|
+
Displays calls on reachable paths from a source function to a target function, showing transitive call graph connectivity.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This query identifies all function calls that lie on any transitive call path from a specified source function to a specified target function. Given both a source and target function name, it reports each call site along the connecting paths, which is useful for understanding indirect call chains, security-relevant data flow paths, and function reachability.
|
|
8
|
+
|
|
9
|
+
The query uses transitive closure (`calls*`) to determine reachability, then reports only the direct call sites that contribute to paths between the source and target. It accepts function names via extensible predicates (`sourceFunction` and `targetFunction`) populated via CodeQL data extensions / model packs (see `ExternalPredicates.qll`).
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Determining if a call path exists between two functions
|
|
16
|
+
- Mapping indirect call chains from a source to a target function
|
|
17
|
+
- Analyzing security-relevant paths (e.g., from user input handlers to sensitive operations)
|
|
18
|
+
- Understanding transitive dependencies between functions
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
The following Go code demonstrates a transitive call chain from `source` through `intermediate` to `target`:
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
func target() {}
|
|
26
|
+
|
|
27
|
+
func intermediate() {
|
|
28
|
+
target()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func source() {
|
|
32
|
+
intermediate()
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Running with `sourceFunction = "source"` and `targetFunction = "target"` produces results showing each call site on the path with a message like: "Reachable call from `source` to `intermediate`".
|
|
37
|
+
|
|
38
|
+
## Output Format
|
|
39
|
+
|
|
40
|
+
The query is a `@kind problem` query producing rows of:
|
|
41
|
+
|
|
42
|
+
- ``select call, "Reachable call from `caller` to `callee`"``
|
|
43
|
+
|
|
44
|
+
## References
|
|
45
|
+
|
|
46
|
+
- [Go Functions](https://go.dev/doc/effective_go#functions)
|
|
47
|
+
- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From To for go
|
|
3
|
+
* @description Displays calls on reachable paths from a source function to a target function, showing transitive call graph connectivity.
|
|
4
|
+
* @id go/tools/call-graph-from-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import go
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single source function name from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getSourceFunctionName() {
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a single target function name from the comma-separated list.
|
|
22
|
+
*/
|
|
23
|
+
string getTargetFunctionName() {
|
|
24
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Holds if function `caller` directly calls function `callee` by name.
|
|
29
|
+
*/
|
|
30
|
+
predicate calls(FuncDecl caller_, FuncDecl callee_) {
|
|
31
|
+
exists(CallExpr c |
|
|
32
|
+
c.getEnclosingFunction() = caller_ and
|
|
33
|
+
c.getTarget().getName() = callee_.getName()
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
from CallExpr call, FuncDecl caller
|
|
38
|
+
where
|
|
39
|
+
call.getEnclosingFunction() = caller and
|
|
40
|
+
exists(
|
|
41
|
+
// Use external predicates if available: show calls on paths from source to target
|
|
42
|
+
FuncDecl source, FuncDecl target
|
|
43
|
+
|
|
|
44
|
+
source.getName() = getSourceFunctionName() and
|
|
45
|
+
target.getName() = getTargetFunctionName() and
|
|
46
|
+
calls*(source, caller) and
|
|
47
|
+
exists(FuncDecl callee |
|
|
48
|
+
call.getTarget().getName() = callee.getName() and
|
|
49
|
+
calls*(callee, target)
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
select call,
|
|
53
|
+
"Reachable call from `" + caller.getName() + "` to `" + call.getTarget().getName() + "`"
|
|
@@ -8,18 +8,13 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import go
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the target function name for which to generate the call graph.
|
|
14
|
-
* Can be a single function name or comma-separated list of function names.
|
|
15
|
-
*/
|
|
16
|
-
external string targetFunction();
|
|
11
|
+
import ExternalPredicates
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Gets a single target function name from the comma-separated list.
|
|
20
15
|
*/
|
|
21
16
|
string getTargetFunctionName() {
|
|
22
|
-
|
|
17
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
/**
|
|
@@ -32,16 +27,5 @@ string getCallerName(CallExpr call) {
|
|
|
32
27
|
}
|
|
33
28
|
|
|
34
29
|
from CallExpr call
|
|
35
|
-
where
|
|
36
|
-
|
|
37
|
-
// Use external predicate if available
|
|
38
|
-
call.getTarget().getName() = getTargetFunctionName()
|
|
39
|
-
or
|
|
40
|
-
// Fallback for unit tests: include test files
|
|
41
|
-
(
|
|
42
|
-
not exists(getTargetFunctionName()) and
|
|
43
|
-
call.getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
44
|
-
)
|
|
45
|
-
)
|
|
46
|
-
select call,
|
|
47
|
-
"Call to `" + call.getTarget().getName() + "` from `" + getCallerName(call) + "`"
|
|
30
|
+
where call.getTarget().getName() = getTargetFunctionName()
|
|
31
|
+
select call, "Call to `" + call.getTarget().getName() + "` from `" + getCallerName(call) + "`"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared extensible predicate declarations for MCP server tools queries.
|
|
3
|
+
* Values are provided via dataExtensions YAML files during testing,
|
|
4
|
+
* or via a temporary data extension pack at runtime from the MCP server.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Holds for each source function name for call graph analysis. */
|
|
8
|
+
extensible predicate sourceFunction(string name);
|
|
9
|
+
|
|
10
|
+
/** Holds for each target function name for call graph analysis. */
|
|
11
|
+
extensible predicate targetFunction(string name);
|
|
12
|
+
|
|
13
|
+
/** Holds for each selected source file path for AST/CFG printing. */
|
|
14
|
+
extensible predicate selectedSourceFiles(string path);
|
|
@@ -7,19 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import go
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the source files to generate AST from.
|
|
14
|
-
* Can be a single file path or comma-separated list of file paths.
|
|
15
|
-
*/
|
|
16
|
-
external string selectedSourceFiles();
|
|
10
|
+
import ExternalPredicates
|
|
17
11
|
|
|
18
12
|
/**
|
|
19
13
|
* Gets a single source file from the comma-separated list.
|
|
20
14
|
*/
|
|
21
15
|
string getSelectedSourceFile() {
|
|
22
|
-
|
|
16
|
+
exists(string s | selectedSourceFiles(s) | result = s.splitAt(",").trim())
|
|
23
17
|
}
|
|
24
18
|
|
|
25
19
|
/**
|
|
@@ -30,29 +24,145 @@ File getSelectedFile() {
|
|
|
30
24
|
selectedFile = getSelectedSourceFile() and
|
|
31
25
|
(
|
|
32
26
|
// Match by exact relative path from source root
|
|
33
|
-
result.getRelativePath() = selectedFile
|
|
27
|
+
result.getRelativePath() = selectedFile
|
|
28
|
+
or
|
|
34
29
|
// Match by file name if no path separators
|
|
35
|
-
|
|
30
|
+
not selectedFile.matches("%/%") and result.getBaseName() = selectedFile
|
|
31
|
+
or
|
|
36
32
|
// Match by ending path component
|
|
37
|
-
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
33
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
34
|
+
selectedFile
|
|
38
35
|
)
|
|
39
36
|
)
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
40
|
+
* Holds if the given file should be printed.
|
|
41
|
+
* Uses the external predicate if available, otherwise falls back to test files.
|
|
42
|
+
*/
|
|
43
|
+
private predicate isSelectedFile(File file) { file = getSelectedFile() }
|
|
44
|
+
|
|
45
|
+
// Standalone PrintAST implementation for Go.
|
|
46
|
+
//
|
|
47
|
+
// This avoids extending the library's `PrintAstConfiguration` (which is inside
|
|
48
|
+
// an `overlay[local]` module in `go-all`) by directly using the Go AST API.
|
|
49
|
+
// File filtering is applied at the source level for efficiency.
|
|
50
|
+
/** Gets the enclosing function declaration for `n`, if any. */
|
|
51
|
+
private FuncDecl getEnclosingFunctionDecl(AstNode n) { result = n.getParent*() }
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Holds if `ast` should be included in the printed AST.
|
|
55
|
+
* Restricts to selected files and excludes comments for deterministic output.
|
|
56
|
+
*/
|
|
57
|
+
private predicate shouldPrint(AstNode ast) {
|
|
58
|
+
isSelectedFile(ast.getFile()) and
|
|
59
|
+
// Print nodes without an enclosing function (e.g. file headers)
|
|
60
|
+
forall(FuncDecl f | f = getEnclosingFunctionDecl(ast) | isSelectedFile(f.getFile())) and
|
|
61
|
+
// Exclude comments for deterministic output
|
|
62
|
+
not ast instanceof Comment and
|
|
63
|
+
not ast instanceof CommentGroup and
|
|
64
|
+
exists(ast.getLocation())
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Gets the QL class label for an AST node. */
|
|
68
|
+
private string qlClass(AstNode el) { result = "[" + concat(el.getAPrimaryQlClass(), ", ") + "] " }
|
|
69
|
+
|
|
70
|
+
/** Gets the default string representation for an AST node. */
|
|
71
|
+
private string nodeToString(AstNode ast) {
|
|
72
|
+
if ast instanceof File
|
|
73
|
+
then result = qlClass(ast) + ast.(File).getRelativePath()
|
|
74
|
+
else result = qlClass(ast) + ast.toString()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Gets the child at `childIndex` for `ast`, with special handling
|
|
79
|
+
* for `File` nodes (package name expression is moved to index 0).
|
|
80
|
+
* Comments are excluded from the child list.
|
|
45
81
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
82
|
+
private AstNode getChild(AstNode ast, int childIndex) {
|
|
83
|
+
if ast instanceof File and exists(ast.(File).getPackageNameExpr())
|
|
84
|
+
then
|
|
85
|
+
exists(AstNode packageNode, int oldPackageIndex |
|
|
86
|
+
ast.getUniquelyNumberedChild(oldPackageIndex) = packageNode and
|
|
87
|
+
packageNode = ast.(File).getPackageNameExpr() and
|
|
88
|
+
(
|
|
89
|
+
childIndex = 0 and result = packageNode
|
|
90
|
+
or
|
|
91
|
+
result =
|
|
92
|
+
rank[childIndex](AstNode node, int i |
|
|
93
|
+
node = ast.getUniquelyNumberedChild(i) and
|
|
94
|
+
i != oldPackageIndex and
|
|
95
|
+
not node instanceof Comment and
|
|
96
|
+
not node instanceof CommentGroup
|
|
97
|
+
|
|
|
98
|
+
node order by i
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
else
|
|
103
|
+
result =
|
|
104
|
+
rank[childIndex](AstNode node, int i |
|
|
105
|
+
node = ast.getUniquelyNumberedChild(i) and
|
|
106
|
+
not node instanceof Comment and
|
|
107
|
+
not node instanceof CommentGroup
|
|
108
|
+
|
|
|
109
|
+
node order by i
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Gets the edge label from `ast` to its child at `childIndex`. */
|
|
114
|
+
private string getChildEdgeLabel(AstNode ast, int childIndex) {
|
|
115
|
+
exists(getChild(ast, childIndex)) and
|
|
116
|
+
if
|
|
117
|
+
ast instanceof File and
|
|
118
|
+
exists(ast.(File).getPackageNameExpr()) and
|
|
119
|
+
getChild(ast, childIndex) = ast.(File).getPackageNameExpr()
|
|
120
|
+
then result = "package"
|
|
121
|
+
else result = childIndex.toString()
|
|
122
|
+
}
|
|
48
123
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
124
|
+
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
|
|
125
|
+
query predicate nodes(AstNode node, string key, string value) {
|
|
126
|
+
shouldPrint(node) and
|
|
127
|
+
(
|
|
128
|
+
key = "semmle.label" and value = nodeToString(node)
|
|
129
|
+
or
|
|
130
|
+
node instanceof Expr and
|
|
131
|
+
(
|
|
132
|
+
key = "Value" and
|
|
133
|
+
value = qlClass(node) + node.(Expr).getExactValue()
|
|
134
|
+
or
|
|
135
|
+
key = "Type" and
|
|
136
|
+
not node.(Expr).getType() instanceof InvalidType and
|
|
137
|
+
value = node.(Expr).getType().pp()
|
|
138
|
+
)
|
|
52
139
|
or
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
140
|
+
node instanceof File and
|
|
141
|
+
key = "semmle.order" and
|
|
142
|
+
value =
|
|
143
|
+
any(int i |
|
|
144
|
+
node = rank[i](File fn | isSelectedFile(fn) | fn order by fn.getRelativePath())
|
|
145
|
+
|
|
|
146
|
+
i
|
|
147
|
+
).toString()
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Holds if `target` is a child of `source` in the AST. */
|
|
152
|
+
query predicate edges(AstNode source, AstNode target, string key, string value) {
|
|
153
|
+
shouldPrint(source) and
|
|
154
|
+
shouldPrint(target) and
|
|
155
|
+
exists(int childIndex |
|
|
156
|
+
target = getChild(source, childIndex) and
|
|
157
|
+
(
|
|
158
|
+
key = "semmle.label" and value = getChildEdgeLabel(source, childIndex)
|
|
159
|
+
or
|
|
160
|
+
key = "semmle.order" and value = childIndex.toString()
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
}
|
|
56
164
|
|
|
57
|
-
|
|
165
|
+
/** Holds if property `key` of the graph has the given `value`. */
|
|
166
|
+
query predicate graphProperties(string key, string value) {
|
|
167
|
+
key = "semmle.graphKind" and value = "tree"
|
|
58
168
|
}
|
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
lockVersion: 1.0.0
|
|
3
3
|
dependencies:
|
|
4
4
|
codeql/concepts:
|
|
5
|
-
version: 0.0.
|
|
5
|
+
version: 0.0.18
|
|
6
6
|
codeql/controlflow:
|
|
7
|
-
version: 2.0.
|
|
7
|
+
version: 2.0.28
|
|
8
8
|
codeql/dataflow:
|
|
9
|
-
version: 2.0
|
|
9
|
+
version: 2.1.0
|
|
10
10
|
codeql/go-all:
|
|
11
|
-
version:
|
|
11
|
+
version: 7.0.2
|
|
12
12
|
codeql/mad:
|
|
13
|
-
version: 1.0.
|
|
13
|
+
version: 1.0.44
|
|
14
14
|
codeql/ssa:
|
|
15
|
-
version: 2.0.
|
|
15
|
+
version: 2.0.20
|
|
16
16
|
codeql/threat-models:
|
|
17
|
-
version: 1.0.
|
|
17
|
+
version: 1.0.44
|
|
18
18
|
codeql/tutorial:
|
|
19
|
-
version: 1.0.
|
|
19
|
+
version: 1.0.44
|
|
20
20
|
codeql/typetracking:
|
|
21
|
-
version: 2.0.25
|
|
22
|
-
codeql/util:
|
|
23
21
|
version: 2.0.28
|
|
22
|
+
codeql/util:
|
|
23
|
+
version: 2.0.31
|
|
24
24
|
compiled: false
|
|
@@ -8,18 +8,13 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import java
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the source method name for which to generate the call graph.
|
|
14
|
-
* Can be a single method name or comma-separated list of method names.
|
|
15
|
-
*/
|
|
16
|
-
external string sourceFunction();
|
|
11
|
+
import ExternalPredicates
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Gets a single source method name from the comma-separated list.
|
|
20
15
|
*/
|
|
21
16
|
string getSourceFunctionName() {
|
|
22
|
-
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
/**
|
|
@@ -36,15 +31,5 @@ from Call call, Callable source, Callable callee
|
|
|
36
31
|
where
|
|
37
32
|
call.getCaller() = source and
|
|
38
33
|
call.getCallee() = callee and
|
|
39
|
-
(
|
|
40
|
-
|
|
41
|
-
source = getSourceFunction()
|
|
42
|
-
or
|
|
43
|
-
// Fallback for unit tests: include test files
|
|
44
|
-
(
|
|
45
|
-
not exists(getSourceFunction()) and
|
|
46
|
-
source.getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
47
|
-
)
|
|
48
|
-
)
|
|
49
|
-
select call,
|
|
50
|
-
"Call from `" + source.getName() + "` to `" + callee.getName() + "`"
|
|
34
|
+
source = getSourceFunction()
|
|
35
|
+
select call, "Call from `" + source.getName() + "` to `" + callee.getName() + "`"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# CallGraphFromTo for Java
|
|
2
|
+
|
|
3
|
+
Displays calls on reachable paths from a source method to a target method, showing transitive call graph connectivity.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This query identifies all method calls that lie on any transitive call path from a specified source method to a specified target method. Given both a source and target method name, it reports each call site along the connecting paths, which is useful for understanding indirect call chains, security-relevant data flow paths, and method reachability.
|
|
8
|
+
|
|
9
|
+
The query uses transitive closure (`calls*`) to determine reachability, then reports only the direct call sites that contribute to paths between the source and target. It accepts method names via extensible predicates (`sourceFunction` and `targetFunction`) populated via CodeQL data extensions / model packs (see `ExternalPredicates.qll`).
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Determining if a call path exists between two methods
|
|
16
|
+
- Mapping indirect call chains from a source to a target method
|
|
17
|
+
- Analyzing security-relevant paths (e.g., from user input handlers to sensitive operations)
|
|
18
|
+
- Understanding transitive dependencies between methods
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
The following Java code demonstrates a transitive call chain from `source` through `intermediate` to `target`:
|
|
23
|
+
|
|
24
|
+
```java
|
|
25
|
+
class Example {
|
|
26
|
+
void target() {}
|
|
27
|
+
|
|
28
|
+
void intermediate() {
|
|
29
|
+
target();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void source() {
|
|
33
|
+
intermediate();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Running with `sourceFunction = "source"` and `targetFunction = "target"` produces results showing each call site on the path with a message like: "Reachable call from `source` to `intermediate`".
|
|
39
|
+
|
|
40
|
+
## Output Format
|
|
41
|
+
|
|
42
|
+
The query is a `@kind problem` query producing rows of:
|
|
43
|
+
|
|
44
|
+
- ``select call, "Reachable call from `caller` to `callee`"``
|
|
45
|
+
|
|
46
|
+
## References
|
|
47
|
+
|
|
48
|
+
- [Java Methods](https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html)
|
|
49
|
+
- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From To for java
|
|
3
|
+
* @description Displays calls on reachable paths from a source method to a target method, showing transitive call graph connectivity.
|
|
4
|
+
* @id java/tools/call-graph-from-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import java
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single source method name from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getSourceFunctionName() {
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a single target method name from the comma-separated list.
|
|
22
|
+
*/
|
|
23
|
+
string getTargetFunctionName() {
|
|
24
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets a method by matching against the selected source method names.
|
|
29
|
+
*/
|
|
30
|
+
Callable getSourceFunction() {
|
|
31
|
+
exists(string selectedFunc |
|
|
32
|
+
selectedFunc = getSourceFunctionName() and
|
|
33
|
+
result.getName() = selectedFunc
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Gets a method by matching against the selected target method names.
|
|
39
|
+
*/
|
|
40
|
+
Callable getTargetFunction() {
|
|
41
|
+
exists(string selectedFunc |
|
|
42
|
+
selectedFunc = getTargetFunctionName() and
|
|
43
|
+
result.getName() = selectedFunc
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Holds if callable `caller` directly calls callable `callee`.
|
|
49
|
+
*/
|
|
50
|
+
predicate calls(Callable caller_, Callable callee_) {
|
|
51
|
+
exists(Call c | c.getCaller() = caller_ and c.getCallee() = callee_)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
from Call call, Callable caller, Callable callee
|
|
55
|
+
where
|
|
56
|
+
call.getCaller() = caller and
|
|
57
|
+
call.getCallee() = callee and
|
|
58
|
+
exists(Callable source, Callable target |
|
|
59
|
+
source = getSourceFunction() and
|
|
60
|
+
target = getTargetFunction() and
|
|
61
|
+
calls*(source, caller) and
|
|
62
|
+
calls*(callee, target)
|
|
63
|
+
)
|
|
64
|
+
select call, "Reachable call from `" + caller.getName() + "` to `" + callee.getName() + "`"
|