forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExternalApi.qll
More file actions
133 lines (113 loc) · 4.74 KB
/
ExternalApi.qll
File metadata and controls
133 lines (113 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/** Provides classes and predicates related to handling APIs from external libraries. */
private import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dataflow.internal.DataFlowPrivate
private import semmle.code.java.dataflow.TaintTracking
/**
* A test library.
*/
private class TestLibrary extends RefType {
TestLibrary() {
this.getPackage()
.getName()
.matches([
"org.junit%", "junit.%", "org.mockito%", "org.assertj%",
"com.github.tomakehurst.wiremock%", "org.hamcrest%", "org.springframework.test.%",
"org.springframework.mock.%", "org.springframework.boot.test.%", "reactor.test%",
"org.xmlunit%", "org.testcontainers.%", "org.opentest4j%", "org.mockserver%",
"org.powermock%", "org.skyscreamer.jsonassert%", "org.rnorth.visibleassertions",
"org.openqa.selenium%", "com.gargoylesoftware.htmlunit%",
"org.jboss.arquillian.testng%", "org.testng%"
])
}
}
private string containerAsJar(Container container) {
if container instanceof JarFile then result = container.getBaseName() else result = "rt.jar"
}
/**
* An external API from either the Standard Library or a 3rd party library.
*/
class ExternalApi extends Callable {
ExternalApi() { not this.fromSource() }
/**
* Gets information about the external API in the form expected by the CSV modeling framework.
*/
string getApiName() {
result =
this.getDeclaringType().getPackage() + "." + this.getDeclaringType().getSourceDeclaration() +
"#" + this.getName() + paramsString(this)
}
/**
* Gets the jar file containing this API. Normalizes the Java Runtime to "rt.jar" despite the presence of modules.
*/
string jarContainer() { result = containerAsJar(this.getCompilationUnit().getParentContainer*()) }
/** Gets a node that is an input to a call to this API. */
private DataFlow::Node getAnInput() {
exists(Call call | call.getCallee().getSourceDeclaration() = this |
result.asExpr().(Argument).getCall() = call or
result.(ArgumentNode).getCall().asCall() = call
)
}
/** Gets a node that is an output from a call to this API. */
private DataFlow::Node getAnOutput() {
exists(Call call | call.getCallee().getSourceDeclaration() = this |
result.asExpr() = call or
result.(DataFlow::PostUpdateNode).getPreUpdateNode().(ArgumentNode).getCall().asCall() = call
)
}
/** Holds if this API has a supported summary. */
predicate hasSummary() {
this instanceof SummarizedCallable or
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
}
/** Holds if this API is is a constructor without parameters. */
private predicate isParameterlessConstructor() {
this instanceof Constructor and this.getNumberOfParameters() = 0
}
/** Holds if this API is part of a common testing library or framework. */
private predicate isTestLibrary() { this.getDeclaringType() instanceof TestLibrary }
/** Holds if this API is not worth supporting. */
predicate isUninteresting() { this.isTestLibrary() or this.isParameterlessConstructor() }
/** Holds if this API is a known source. */
predicate isSource() {
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
}
/** Holds if this API is a known sink. */
predicate isSink() { sinkNode(this.getAnInput(), _) }
/** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */
predicate isSupported() { this.hasSummary() or this.isSource() or this.isSink() }
}
/** DEPRECATED: Alias for ExternalApi */
deprecated class ExternalAPI = ExternalApi;
/**
* Gets the limit for the number of results produced by a telemetry query.
*/
int resultLimit() { result = 1000 }
/**
* Holds if the relevant usage count of `api` is `usages`.
*/
signature predicate relevantUsagesSig(ExternalApi api, int usages);
/**
* Given a predicate to count relevant API usages, this module provides a predicate
* for restricting the number or returned results based on a certain limit.
*/
module Results<relevantUsagesSig/2 getRelevantUsages> {
private int getOrder(ExternalApi api) {
api =
rank[result](ExternalApi a, int usages |
getRelevantUsages(a, usages)
|
a order by usages desc, a.getApiName()
)
}
/**
* Holds if `api` is being used `usages` times and if it is
* in the top results (guarded by resultLimit).
*/
predicate restrict(ExternalApi api, int usages) {
getRelevantUsages(api, usages) and getOrder(api) <= resultLimit()
}
}