Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: Add VS Code model editor queries #14199

Merged
merged 15 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class TestLibrary extends RefType {
}

/** Holds if the given file is a test file. */
private predicate isInTestFile(File file) {
predicate isInTestFile(File file) {
file.getAbsolutePath().matches(["%/test/%", "%/guava-tests/%", "%/guava-testlib/%"]) and
not file.getAbsolutePath().matches(["%/ql/test/%", "%/ql/automodel/test/%"]) // allows our test cases to work
}
Expand Down
139 changes: 139 additions & 0 deletions java/ql/src/utils/modeleditor/AutomodelVsCode.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/** Provides classes and predicates related to handling APIs for the VS Code extension. */

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.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.internal.ModelExclusions

/** Holds if the given callable/method is not worth supporting. */
private predicate isUninteresting(Callable c) {
c.getDeclaringType() instanceof TestLibrary or
c.(Constructor).isParameterless() or
c.getDeclaringType() instanceof AnonymousClass
}

/**
* A callable method from either the Standard Library, a 3rd party library or from the source.
*/
class CallableMethod extends Callable {
CallableMethod() { not isUninteresting(this) }

/**
* Gets information about the external API in the form expected by the MaD modeling framework.
*/
string getApiName() {
result =
this.getDeclaringType().getPackage() + "." + this.getDeclaringType().nestedName() + "#" +
this.getName() + paramsString(this)
}

private string getJarName() {
result = this.getCompilationUnit().getParentContainer*().(JarFile).getBaseName()
}

private string getJarVersion() {
result = this.getCompilationUnit().getParentContainer*().(JarFile).getSpecificationVersion()
}

/**
* Gets the jar file containing this API. Normalizes the Java Runtime to "rt.jar" despite the presence of modules.
*/
string jarContainer() {
result = this.getJarName()
or
not exists(this.getJarName()) and result = "rt.jar"
}

/**
* Gets the version of the JAR file containing this API. Empty if no version is found in the JAR.
*/
string jarVersion() {
result = this.getJarVersion()
or
not exists(this.getJarVersion()) and result = ""
}

/** 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. */
pragma[nomagic]
predicate hasSummary() {
this = any(SummarizedCallable sc).asCallable() or
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
}

pragma[nomagic]
predicate isSource() {
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
}

/** Holds if this API is a known sink. */
pragma[nomagic]
predicate isSink() { sinkNode(this.getAnInput(), _) }

/** Holds if this API is a known neutral. */
pragma[nomagic]
predicate isNeutral() {
exists(
string namespace, string type, string name, string signature, string kind, string provenance
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
|
neutralModel(namespace, type, name, signature, kind, provenance) and
this = interpretElement(namespace, type, false, name, signature, "")
)
}

/**
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a
* recognized source, sink or neutral or it has a flow summary.
*/
predicate isSupported() {
this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
}
}

boolean isSupported(CallableMethod method) {
method.isSupported() and result = true
or
not method.isSupported() and result = false
}

string supportedType(CallableMethod method) {
method.isSink() and result = "sink"
or
method.isSource() and result = "source"
or
method.hasSummary() and result = "summary"
or
method.isNeutral() and result = "neutral"
or
not method.isSupported() and result = ""
}

string methodClassification(Call method) {
isInTestFile(method.getLocation().getFile()) and result = "test"
or
method.getFile() instanceof GeneratedFile and result = "generated"
or
not isInTestFile(method.getLocation().getFile()) and
not method.getFile() instanceof GeneratedFile and
result = "source"
}
29 changes: 29 additions & 0 deletions java/ql/src/utils/modeleditor/FetchApplicationModeMethods.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @name Fetch model editor methods (application mode)
* @description A list of 3rd party APIs used in the codebase. Excludes test and generated code.
* @kind problem
* @problem.severity recommendation
* @id java/utils/modeleditor/fetch-application-mode-methods
* @tags modeleditor fetch methods application-mode
*/

private import java
private import AutomodelVsCode

class ExternalApi extends CallableMethod {
ExternalApi() { not this.fromSource() }
}

private Call aUsage(ExternalApi api) { result.getCallee().getSourceDeclaration() = api }

from
ExternalApi externalApi, string apiName, boolean supported, Call usage, string type,
string classification
where
apiName = externalApi.getApiName() and
supported = isSupported(externalApi) and
usage = aUsage(externalApi) and
type = supportedType(externalApi) and
classification = methodClassification(usage)
select usage, apiName, supported.toString(), "supported", externalApi.jarContainer(),
externalApi.jarVersion(), type, "type", classification, "classification"
23 changes: 23 additions & 0 deletions java/ql/src/utils/modeleditor/FetchFrameworkModeMethods.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @name Fetch model editor methods (framework mode)
* @description A list of APIs callable by consumers. Excludes test and generated code.
* @kind problem
* @problem.severity recommendation
* @id java/utils/modeleditor/fetch-framework-mode-methods
* @tags modeleditor fetch methods framework-mode
*/

private import java
private import semmle.code.java.dataflow.internal.ModelExclusions
private import AutomodelVsCode

class PublicMethodFromSource extends CallableMethod, ModelApi { }

from PublicMethodFromSource publicMethod, string apiName, boolean supported, string type
where
apiName = publicMethod.getApiName() and
supported = isSupported(publicMethod) and
type = supportedType(publicMethod)
select publicMethod, apiName, supported.toString(), "supported",
publicMethod.getCompilationUnit().getParentContainer().getBaseName(), "library", type, "type",
"unknown", "classification"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
| com/github/codeql/test/NonPublicClass.java:5:5:5:28 | println(...) | java.io.PrintStream#println(String) | true | supported | rt.jar | | sink | type | source | classification |
| com/github/codeql/test/PublicClass.java:7:5:7:27 | println(...) | java.io.PrintStream#println(String) | true | supported | rt.jar | | sink | type | source | classification |
| com/github/codeql/test/PublicClass.java:11:5:11:27 | println(...) | java.io.PrintStream#println(String) | true | supported | rt.jar | | sink | type | source | classification |
| com/github/codeql/test/PublicClass.java:15:5:15:45 | println(...) | java.io.PrintStream#println(Object) | true | supported | rt.jar | | sink | type | source | classification |
| com/github/codeql/test/PublicClass.java:15:24:15:44 | get(...) | java.nio.file.Paths#get(String,String[]) | true | supported | rt.jar | | sink | type | source | classification |
| com/github/codeql/test/PublicClass.java:15:24:15:44 | get(...) | java.nio.file.Paths#get(String,String[]) | true | supported | rt.jar | | summary | type | source | classification |
| com/github/codeql/test/PublicClass.java:19:5:19:27 | println(...) | java.io.PrintStream#println(String) | true | supported | rt.jar | | sink | type | source | classification |
| com/github/codeql/test/PublicInterface.java:7:7:7:29 | println(...) | java.io.PrintStream#println(String) | true | supported | rt.jar | | sink | type | source | classification |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
utils/modeleditor/FetchApplicationModeMethods.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
| com/github/codeql/test/PublicClass.java:6:15:6:19 | stuff | com.github.codeql.test.PublicClass#stuff(String) | false | supported | test | library | | type | unknown | classification |
| com/github/codeql/test/PublicClass.java:10:22:10:32 | staticStuff | com.github.codeql.test.PublicClass#staticStuff(String) | false | supported | test | library | | type | unknown | classification |
| com/github/codeql/test/PublicClass.java:14:18:14:31 | nonPublicStuff | com.github.codeql.test.PublicClass#nonPublicStuff(String) | false | supported | test | library | | type | unknown | classification |
| com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | com.github.codeql.test.PublicInterface#stuff(String) | false | supported | test | library | | type | unknown | classification |
| com/github/codeql/test/PublicInterface.java:6:24:6:34 | staticStuff | com.github.codeql.test.PublicInterface#staticStuff(String) | false | supported | test | library | | type | unknown | classification |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
utils/modeleditor/FetchFrameworkModeMethods.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.codeql.test;

class NonPublicClass {
public void noCandidates(String here) {
System.out.println(here);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.github.codeql.test;

import java.nio.file.Paths;

public class PublicClass {
public void stuff(String arg) {
System.out.println(arg);
}

public static void staticStuff(String arg) {
System.out.println(arg);
}

protected void nonPublicStuff(String arg) {
System.out.println(Paths.get("foo", arg));
}

void packagePrivateStuff(String arg) {
System.out.println(arg);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.github.codeql.test;

public interface PublicInterface {
public void stuff(String arg);

public static void staticStuff(String arg) {
System.out.println(arg);
}
}
1 change: 1 addition & 0 deletions misc/suite-helpers/code-scanning-selectors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@
- /Diagnostics/Internal/.*/
- exclude:
tags contain:
- modeleditor
- modelgenerator
1 change: 1 addition & 0 deletions misc/suite-helpers/security-and-quality-selectors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@
- /Diagnostics/Internal/.*/
- exclude:
tags contain:
- modeleditor
- modelgenerator
1 change: 1 addition & 0 deletions misc/suite-helpers/security-experimental-selectors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@
- /Diagnostics/Internal/.*/
- exclude:
tags contain:
- modeleditor
- model-generator
1 change: 1 addition & 0 deletions misc/suite-helpers/security-extended-selectors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@
- /Diagnostics/Internal/.*/
- exclude:
tags contain:
- modeleditor
- modelgenerator