Skip to content

Commit 10231e9

Browse files
authored
Merge pull request github#14199 from github/koesie10/add-java-model-editor-queries
Java: Add VS Code model editor queries
2 parents 0f4f987 + ced95e0 commit 10231e9

16 files changed

+354
-1
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/ModelExclusions.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class TestLibrary extends RefType {
2525
}
2626

2727
/** Holds if the given file is a test file. */
28-
private predicate isInTestFile(File file) {
28+
predicate isInTestFile(File file) {
2929
file.getAbsolutePath().matches(["%/test/%", "%/guava-tests/%", "%/guava-testlib/%"]) and
3030
not file.getAbsolutePath().matches(["%/ql/test/%", "%/ql/automodel/test/%"]) // allows our test cases to work
3131
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @name Fetch endpoints for use in the model editor (application mode)
3+
* @description A list of 3rd party endpoints (methods) used in the codebase. Excludes test and generated code.
4+
* @kind table
5+
* @id java/utils/modeleditor/application-mode-endpoints
6+
* @tags modeleditor endpoints application-mode
7+
*/
8+
9+
private import java
10+
private import ApplicationModeEndpointsQuery
11+
private import ModelEditor
12+
13+
private Call aUsage(ExternalEndpoint endpoint) {
14+
result.getCallee().getSourceDeclaration() = endpoint
15+
}
16+
17+
from ExternalEndpoint endpoint, boolean supported, Call usage, string type, string classification
18+
where
19+
supported = isSupported(endpoint) and
20+
usage = aUsage(endpoint) and
21+
type = supportedType(endpoint) and
22+
classification = usageClassification(usage)
23+
select usage, endpoint.getPackageName(), endpoint.getTypeName(), endpoint.getName(),
24+
endpoint.getParameterTypes(), supported, endpoint.jarContainer(), endpoint.jarVersion(), type,
25+
classification
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
private import java
2+
private import semmle.code.java.dataflow.ExternalFlow
3+
private import semmle.code.java.dataflow.FlowSources
4+
private import semmle.code.java.dataflow.internal.DataFlowPrivate
5+
private import ModelEditor
6+
7+
/**
8+
* A class of effectively public callables in library code.
9+
*/
10+
class ExternalEndpoint extends Endpoint {
11+
ExternalEndpoint() { not this.fromSource() }
12+
13+
/** Gets a node that is an input to a call to this API. */
14+
private DataFlow::Node getAnInput() {
15+
exists(Call call | call.getCallee().getSourceDeclaration() = this |
16+
result.asExpr().(Argument).getCall() = call or
17+
result.(ArgumentNode).getCall().asCall() = call
18+
)
19+
}
20+
21+
/** Gets a node that is an output from a call to this API. */
22+
private DataFlow::Node getAnOutput() {
23+
exists(Call call | call.getCallee().getSourceDeclaration() = this |
24+
result.asExpr() = call or
25+
result.(DataFlow::PostUpdateNode).getPreUpdateNode().(ArgumentNode).getCall().asCall() = call
26+
)
27+
}
28+
29+
override predicate hasSummary() {
30+
Endpoint.super.hasSummary()
31+
or
32+
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
33+
}
34+
35+
override predicate isSource() {
36+
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
37+
}
38+
39+
override predicate isSink() { sinkNode(this.getAnInput(), _) }
40+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @name Fetch endpoints for use in the model editor (framework mode)
3+
* @description A list of endpoints accessible (methods) for consumers of the library. Excludes test and generated code.
4+
* @kind table
5+
* @id java/utils/modeleditor/framework-mode-endpoints
6+
* @tags modeleditor endpoints framework-mode
7+
*/
8+
9+
private import java
10+
private import FrameworkModeEndpointsQuery
11+
private import ModelEditor
12+
13+
from PublicEndpointFromSource endpoint, boolean supported, string type
14+
where
15+
supported = isSupported(endpoint) and
16+
type = supportedType(endpoint)
17+
select endpoint, endpoint.getPackageName(), endpoint.getTypeName(), endpoint.getName(),
18+
endpoint.getParameterTypes(), supported,
19+
endpoint.getCompilationUnit().getParentContainer().getBaseName(), type
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
private import java
2+
private import semmle.code.java.dataflow.internal.DataFlowPrivate
3+
private import semmle.code.java.dataflow.internal.FlowSummaryImplSpecific
4+
private import semmle.code.java.dataflow.internal.ModelExclusions
5+
private import ModelEditor
6+
7+
/**
8+
* A class of effectively public callables from source code.
9+
*/
10+
class PublicEndpointFromSource extends Endpoint, ModelApi {
11+
override predicate isSource() { sourceElement(this, _, _, _) }
12+
13+
override predicate isSink() { sinkElement(this, _, _, _) }
14+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/** Provides classes and predicates related to handling APIs for the VS Code extension. */
2+
3+
private import java
4+
private import semmle.code.java.dataflow.ExternalFlow
5+
private import semmle.code.java.dataflow.FlowSummary
6+
private import semmle.code.java.dataflow.TaintTracking
7+
private import semmle.code.java.dataflow.internal.ModelExclusions
8+
9+
/** Holds if the given callable/method is not worth supporting. */
10+
private predicate isUninteresting(Callable c) {
11+
c.getDeclaringType() instanceof TestLibrary or
12+
c.(Constructor).isParameterless() or
13+
c.getDeclaringType() instanceof AnonymousClass
14+
}
15+
16+
/**
17+
* A callable method from either the Standard Library, a 3rd party library or from the source.
18+
*/
19+
class Endpoint extends Callable {
20+
Endpoint() { not isUninteresting(this) }
21+
22+
/**
23+
* Gets the package name of this endpoint.
24+
*/
25+
string getPackageName() { result = this.getDeclaringType().getPackage().getName() }
26+
27+
/**
28+
* Gets the type name of this endpoint.
29+
*/
30+
string getTypeName() { result = this.getDeclaringType().nestedName() }
31+
32+
/**
33+
* Gets the parameter types of this endpoint.
34+
*/
35+
string getParameterTypes() { result = paramsString(this) }
36+
37+
private string getJarName() {
38+
result = this.getCompilationUnit().getParentContainer*().(JarFile).getBaseName()
39+
}
40+
41+
private string getJarVersion() {
42+
result = this.getCompilationUnit().getParentContainer*().(JarFile).getSpecificationVersion()
43+
}
44+
45+
/**
46+
* Gets the jar file containing this API. Normalizes the Java Runtime to "rt.jar" despite the presence of modules.
47+
*/
48+
string jarContainer() {
49+
result = this.getJarName()
50+
or
51+
not exists(this.getJarName()) and result = "rt.jar"
52+
}
53+
54+
/**
55+
* Gets the version of the JAR file containing this API. Empty if no version is found in the JAR.
56+
*/
57+
string jarVersion() {
58+
result = this.getJarVersion()
59+
or
60+
not exists(this.getJarVersion()) and result = ""
61+
}
62+
63+
/** Holds if this API has a supported summary. */
64+
pragma[nomagic]
65+
predicate hasSummary() { this = any(SummarizedCallable sc).asCallable() }
66+
67+
/** Holds if this API is a known source. */
68+
pragma[nomagic]
69+
abstract predicate isSource();
70+
71+
/** Holds if this API is a known sink. */
72+
pragma[nomagic]
73+
abstract predicate isSink();
74+
75+
/** Holds if this API is a known neutral. */
76+
pragma[nomagic]
77+
predicate isNeutral() {
78+
exists(string namespace, string type, string name, string signature |
79+
neutralModel(namespace, type, name, signature, _, _) and
80+
this = interpretElement(namespace, type, false, name, signature, "")
81+
)
82+
}
83+
84+
/**
85+
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a
86+
* recognized source, sink or neutral or it has a flow summary.
87+
*/
88+
predicate isSupported() {
89+
this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
90+
}
91+
}
92+
93+
boolean isSupported(Endpoint endpoint) {
94+
endpoint.isSupported() and result = true
95+
or
96+
not endpoint.isSupported() and result = false
97+
}
98+
99+
string supportedType(Endpoint endpoint) {
100+
endpoint.isSink() and result = "sink"
101+
or
102+
endpoint.isSource() and result = "source"
103+
or
104+
endpoint.hasSummary() and result = "summary"
105+
or
106+
endpoint.isNeutral() and result = "neutral"
107+
or
108+
not endpoint.isSupported() and result = ""
109+
}
110+
111+
string usageClassification(Call usage) {
112+
isInTestFile(usage.getLocation().getFile()) and result = "test"
113+
or
114+
usage.getFile() instanceof GeneratedFile and result = "generated"
115+
or
116+
not isInTestFile(usage.getLocation().getFile()) and
117+
not usage.getFile() instanceof GeneratedFile and
118+
result = "source"
119+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
| com/github/codeql/test/NonPublicClass.java:5:5:5:28 | println(...) | java.io | PrintStream | println | (String) | true | rt.jar | | sink | source |
2+
| com/github/codeql/test/PublicClass.java:8:5:8:27 | println(...) | java.io | PrintStream | println | (String) | true | rt.jar | | sink | source |
3+
| com/github/codeql/test/PublicClass.java:12:5:12:27 | println(...) | java.io | PrintStream | println | (String) | true | rt.jar | | sink | source |
4+
| com/github/codeql/test/PublicClass.java:16:5:16:45 | println(...) | java.io | PrintStream | println | (Object) | true | rt.jar | | sink | source |
5+
| com/github/codeql/test/PublicClass.java:16:24:16:44 | get(...) | java.nio.file | Paths | get | (String,String[]) | true | rt.jar | | sink | source |
6+
| com/github/codeql/test/PublicClass.java:16:24:16:44 | get(...) | java.nio.file | Paths | get | (String,String[]) | true | rt.jar | | summary | source |
7+
| com/github/codeql/test/PublicClass.java:20:5:20:68 | println(...) | java.io | PrintStream | println | (Object) | true | rt.jar | | sink | source |
8+
| com/github/codeql/test/PublicClass.java:20:24:20:47 | getDefault(...) | java.nio.file | FileSystems | getDefault | () | false | rt.jar | | | source |
9+
| com/github/codeql/test/PublicClass.java:20:24:20:67 | getPath(...) | java.nio.file | FileSystem | getPath | (String,String[]) | true | rt.jar | | sink | source |
10+
| com/github/codeql/test/PublicClass.java:20:24:20:67 | getPath(...) | java.nio.file | FileSystem | getPath | (String,String[]) | true | rt.jar | | summary | source |
11+
| com/github/codeql/test/PublicClass.java:24:5:24:27 | println(...) | java.io | PrintStream | println | (String) | true | rt.jar | | sink | source |
12+
| com/github/codeql/test/PublicGenericClass.java:7:5:7:27 | println(...) | java.io | PrintStream | println | (Object) | true | rt.jar | | sink | source |
13+
| com/github/codeql/test/PublicGenericClass.java:11:5:11:27 | println(...) | java.io | PrintStream | println | (Object) | true | rt.jar | | sink | source |
14+
| com/github/codeql/test/PublicGenericInterface.java:8:7:8:29 | println(...) | java.io | PrintStream | println | (String) | true | rt.jar | | sink | source |
15+
| com/github/codeql/test/PublicInterface.java:7:7:7:29 | println(...) | java.io | PrintStream | println | (String) | true | rt.jar | | sink | source |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
utils/modeleditor/ApplicationModeEndpoints.ql
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
| com/github/codeql/test/PublicClass.java:7:15:7:19 | stuff | com.github.codeql.test | PublicClass | stuff | (String) | false | test | |
2+
| com/github/codeql/test/PublicClass.java:11:22:11:32 | staticStuff | com.github.codeql.test | PublicClass | staticStuff | (String) | false | test | |
3+
| com/github/codeql/test/PublicClass.java:15:18:15:31 | protectedStuff | com.github.codeql.test | PublicClass | protectedStuff | (String) | false | test | |
4+
| com/github/codeql/test/PublicClass.java:27:17:27:28 | summaryStuff | com.github.codeql.test | PublicClass | summaryStuff | (String) | true | test | summary |
5+
| com/github/codeql/test/PublicClass.java:31:17:31:27 | sourceStuff | com.github.codeql.test | PublicClass | sourceStuff | () | true | test | source |
6+
| com/github/codeql/test/PublicClass.java:35:15:35:23 | sinkStuff | com.github.codeql.test | PublicClass | sinkStuff | (String) | true | test | sink |
7+
| com/github/codeql/test/PublicClass.java:39:15:39:26 | neutralStuff | com.github.codeql.test | PublicClass | neutralStuff | (String) | true | test | neutral |
8+
| com/github/codeql/test/PublicGenericClass.java:6:15:6:19 | stuff | com.github.codeql.test | PublicGenericClass | stuff | (Object) | false | test | |
9+
| com/github/codeql/test/PublicGenericClass.java:10:20:10:25 | stuff2 | com.github.codeql.test | PublicGenericClass | stuff2 | (Object) | false | test | |
10+
| com/github/codeql/test/PublicGenericInterface.java:4:17:4:21 | stuff | com.github.codeql.test | PublicGenericInterface | stuff | (Object) | false | test | |
11+
| com/github/codeql/test/PublicGenericInterface.java:5:22:5:27 | stuff2 | com.github.codeql.test | PublicGenericInterface | stuff2 | (Object) | false | test | |
12+
| com/github/codeql/test/PublicGenericInterface.java:7:24:7:34 | staticStuff | com.github.codeql.test | PublicGenericInterface | staticStuff | (String) | false | test | |
13+
| com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | com.github.codeql.test | PublicInterface | stuff | (String) | false | test | |
14+
| com/github/codeql/test/PublicInterface.java:6:24:6:34 | staticStuff | com.github.codeql.test | PublicInterface | staticStuff | (String) | false | test | |
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/java-all
4+
extensible: sourceModel
5+
data:
6+
- ["com.github.codeql.test","PublicClass",true,"sourceStuff","()","","ReturnValue","remote","manual"]
7+
8+
- addsTo:
9+
pack: codeql/java-all
10+
extensible: sinkModel
11+
data:
12+
- ["com.github.codeql.test","PublicClass",true,"sinkStuff","(String)","","Argument[0]","sql-injection","manual"]
13+
14+
- addsTo:
15+
pack: codeql/java-all
16+
extensible: summaryModel
17+
data:
18+
- ["com.github.codeql.test","PublicClass",true,"summaryStuff","(String)","","Argument[0]","ReturnValue","taint","manual"]
19+
20+
- addsTo:
21+
pack: codeql/java-all
22+
extensible: neutralModel
23+
data:
24+
- ["com.github.codeql.test","PublicClass","neutralStuff","(String)","summary","manual"]

0 commit comments

Comments
 (0)