mirror of
https://github.com/github/codeql.git
synced 2026-04-18 21:44:02 +02:00
Merge tag 'codeql-cli/v2.18.1' into amammad-java-JWT
Compatible with CodeQL CLI 2.18.1
This commit is contained in:
@@ -1,3 +1,24 @@
|
||||
## 1.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The heuristic to enable certain Android queries has been improved. Now it ignores Android Manifests which don't define an activity, content provider or service. We also only consider files which are under a folder containing such an Android Manifest for these queries. This should remove some false positive alerts.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The query `java/weak-cryptographic-algorithm` no longer alerts about `RSA/ECB` algorithm strings.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `java/tainted-permissions-check` now uses threat models. This means that `local` sources are no longer included by default for this query, but can be added by enabling the `local` threat model.
|
||||
* Added more `org.apache.commons.io.FileUtils`-related sinks to the path injection query.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* or comments.
|
||||
* @kind metric
|
||||
* @tags summary
|
||||
* debug
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* or comments.
|
||||
* @kind metric
|
||||
* @tags summary
|
||||
* debug
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @id java/non-https-url
|
||||
* @tags security
|
||||
* external/cwe/cwe-319
|
||||
* external/cwe/cwe-345
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
65
java/ql/src/Telemetry/DatabaseQuality.qll
Normal file
65
java/ql/src/Telemetry/DatabaseQuality.qll
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Provides database quality statistics that are reported by java/telemetry/extractor-information
|
||||
* and perhaps warned about by java/diagnostics/database-quality.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
signature module StatsSig {
|
||||
int getNumberOfOk();
|
||||
|
||||
int getNumberOfNotOk();
|
||||
|
||||
string getOkText();
|
||||
|
||||
string getNotOkText();
|
||||
}
|
||||
|
||||
module ReportStats<StatsSig Stats> {
|
||||
predicate numberOfOk(string key, int value) {
|
||||
value = Stats::getNumberOfOk() and
|
||||
key = "Number of " + Stats::getOkText()
|
||||
}
|
||||
|
||||
predicate numberOfNotOk(string key, int value) {
|
||||
value = Stats::getNumberOfNotOk() and
|
||||
key = "Number of " + Stats::getNotOkText()
|
||||
}
|
||||
|
||||
predicate percentageOfOk(string key, float value) {
|
||||
value = Stats::getNumberOfOk() * 100.0 / (Stats::getNumberOfOk() + Stats::getNumberOfNotOk()) and
|
||||
key = "Percentage of " + Stats::getOkText()
|
||||
}
|
||||
}
|
||||
|
||||
module CallTargetStats implements StatsSig {
|
||||
int getNumberOfOk() { result = count(Call c | exists(c.getCallee())) }
|
||||
|
||||
int getNumberOfNotOk() { result = count(Call c | not exists(c.getCallee())) }
|
||||
|
||||
string getOkText() { result = "calls with call target" }
|
||||
|
||||
string getNotOkText() { result = "calls with missing call target" }
|
||||
}
|
||||
|
||||
private class SourceExpr extends Expr {
|
||||
SourceExpr() { this.getFile().isSourceFile() }
|
||||
}
|
||||
|
||||
private predicate hasGoodType(Expr e) {
|
||||
exists(e.getType()) and not e.getType() instanceof ErrorType
|
||||
}
|
||||
|
||||
module ExprTypeStats implements StatsSig {
|
||||
int getNumberOfOk() { result = count(SourceExpr e | hasGoodType(e)) }
|
||||
|
||||
int getNumberOfNotOk() { result = count(SourceExpr e | not hasGoodType(e)) }
|
||||
|
||||
string getOkText() { result = "expressions with known type" }
|
||||
|
||||
string getNotOkText() { result = "expressions with unknown type" }
|
||||
}
|
||||
|
||||
module CallTargetStatsReport = ReportStats<CallTargetStats>;
|
||||
|
||||
module ExprTypeStatsReport = ReportStats<ExprTypeStats>;
|
||||
44
java/ql/src/Telemetry/DatabaseQualityDiagnostics.ql
Normal file
44
java/ql/src/Telemetry/DatabaseQualityDiagnostics.ql
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @name Low Java analysis quality
|
||||
* @description Low Java analysis quality
|
||||
* @kind diagnostic
|
||||
* @id java/diagnostic/database-quality
|
||||
*/
|
||||
|
||||
import java
|
||||
import DatabaseQuality
|
||||
|
||||
private newtype TDbQualityDiagnostic =
|
||||
TTheDbQualityDiagnostic() {
|
||||
exists(float percentageGood |
|
||||
CallTargetStatsReport::percentageOfOk(_, percentageGood)
|
||||
or
|
||||
ExprTypeStatsReport::percentageOfOk(_, percentageGood)
|
||||
|
|
||||
percentageGood < 95
|
||||
)
|
||||
}
|
||||
|
||||
class DbQualityDiagnostic extends TDbQualityDiagnostic {
|
||||
string toString() {
|
||||
result =
|
||||
"Scanning Java code completed successfully, but the scan encountered issues. " +
|
||||
"This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- "
|
||||
+
|
||||
"see other CodeQL diagnostics reported on the CodeQL status page for more details of possible causes. "
|
||||
+
|
||||
"Addressing these warnings is advisable to avoid false-positive or missing results. If they cannot be addressed, consider scanning Java "
|
||||
+
|
||||
"using either the `autobuild` or `manual` [build modes](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#comparison-of-the-build-modes)."
|
||||
}
|
||||
}
|
||||
|
||||
query predicate diagnosticAttributes(DbQualityDiagnostic e, string key, string value) {
|
||||
e = e and // Quieten warning about unconstrained 'e'
|
||||
key = ["visibilityCliSummaryTable", "visibilityTelemetry", "visibilityStatusPage"] and
|
||||
value = "true"
|
||||
}
|
||||
|
||||
from DbQualityDiagnostic d
|
||||
select d, d.toString(), 1
|
||||
/* Warning severity */
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.Diagnostics
|
||||
import DatabaseQuality
|
||||
|
||||
extensible predicate extractorInformationSkipKey(string key);
|
||||
|
||||
@@ -85,65 +86,6 @@ predicate extractorTotalDiagnostics(string key, int value) {
|
||||
)
|
||||
}
|
||||
|
||||
signature module StatsSig {
|
||||
int getNumberOfOk();
|
||||
|
||||
int getNumberOfNotOk();
|
||||
|
||||
string getOkText();
|
||||
|
||||
string getNotOkText();
|
||||
}
|
||||
|
||||
module ReportStats<StatsSig Stats> {
|
||||
predicate numberOfOk(string key, int value) {
|
||||
value = Stats::getNumberOfOk() and
|
||||
key = "Number of " + Stats::getOkText()
|
||||
}
|
||||
|
||||
predicate numberOfNotOk(string key, int value) {
|
||||
value = Stats::getNumberOfNotOk() and
|
||||
key = "Number of " + Stats::getNotOkText()
|
||||
}
|
||||
|
||||
predicate percentageOfOk(string key, float value) {
|
||||
value = Stats::getNumberOfOk() * 100.0 / (Stats::getNumberOfOk() + Stats::getNumberOfNotOk()) and
|
||||
key = "Percentage of " + Stats::getOkText()
|
||||
}
|
||||
}
|
||||
|
||||
module CallTargetStats implements StatsSig {
|
||||
int getNumberOfOk() { result = count(Call c | exists(c.getCallee())) }
|
||||
|
||||
int getNumberOfNotOk() { result = count(Call c | not exists(c.getCallee())) }
|
||||
|
||||
string getOkText() { result = "calls with call target" }
|
||||
|
||||
string getNotOkText() { result = "calls with missing call target" }
|
||||
}
|
||||
|
||||
private class SourceExpr extends Expr {
|
||||
SourceExpr() { this.getFile().isSourceFile() }
|
||||
}
|
||||
|
||||
private predicate hasGoodType(Expr e) {
|
||||
exists(e.getType()) and not e.getType() instanceof ErrorType
|
||||
}
|
||||
|
||||
module ExprTypeStats implements StatsSig {
|
||||
int getNumberOfOk() { result = count(SourceExpr e | hasGoodType(e)) }
|
||||
|
||||
int getNumberOfNotOk() { result = count(SourceExpr e | not hasGoodType(e)) }
|
||||
|
||||
string getOkText() { result = "expressions with known type" }
|
||||
|
||||
string getNotOkText() { result = "expressions with unknown type" }
|
||||
}
|
||||
|
||||
module CallTargetStatsReport = ReportStats<CallTargetStats>;
|
||||
|
||||
module ExprTypeStatsReport = ReportStats<ExprTypeStats>;
|
||||
|
||||
from string key, int value
|
||||
where
|
||||
not exists(string pattern | extractorInformationSkipKey(pattern) and key.matches(pattern)) and
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* The query `java/weak-cryptographic-algorithm` no longer alerts about `RSA/ECB` algorithm strings.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added more `org.apache.commons.io.FileUtils`-related sinks to the path injection query.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `java/tainted-permissions-check` now uses threat models. This means that `local` sources are no longer included by default for this query, but can be added by enabling the `local` threat model.
|
||||
3
java/ql/src/change-notes/released/1.0.2.md
Normal file
3
java/ql/src/change-notes/released/1.0.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
10
java/ql/src/change-notes/released/1.1.0.md
Normal file
10
java/ql/src/change-notes/released/1.1.0.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## 1.1.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The query `java/weak-cryptographic-algorithm` no longer alerts about `RSA/ECB` algorithm strings.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `java/tainted-permissions-check` now uses threat models. This means that `local` sources are no longer included by default for this query, but can be added by enabling the `local` threat model.
|
||||
* Added more `org.apache.commons.io.FileUtils`-related sinks to the path injection query.
|
||||
5
java/ql/src/change-notes/released/1.1.1.md
Normal file
5
java/ql/src/change-notes/released/1.1.1.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 1.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The heuristic to enable certain Android queries has been improved. Now it ignores Android Manifests which don't define an activity, content provider or service. We also only consider files which are under a folder containing such an Android Manifest for these queries. This should remove some false positive alerts.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
lastReleaseVersion: 1.1.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-queries
|
||||
version: 1.0.2-dev
|
||||
version: 1.1.1
|
||||
groups:
|
||||
- java
|
||||
- queries
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
import internal.CaptureModels
|
||||
import internal.CaptureSummaryFlowQuery
|
||||
|
||||
from DataFlowTargetApi api, string noflow
|
||||
from DataFlowSummaryTargetApi api, string noflow
|
||||
where noflow = captureNoFlow(api)
|
||||
select noflow order by noflow
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
from DataFlowTargetApi api, string sink
|
||||
from DataFlowSinkTargetApi api, string sink
|
||||
where sink = captureSink(api)
|
||||
select sink order by sink
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
|
||||
import internal.CaptureModels
|
||||
|
||||
from DataFlowTargetApi api, string source
|
||||
from DataFlowSourceTargetApi api, string source
|
||||
where source = captureSource(api)
|
||||
select source order by source
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
import internal.CaptureModels
|
||||
import internal.CaptureSummaryFlowQuery
|
||||
|
||||
from DataFlowTargetApi api, string flow
|
||||
from DataFlowSummaryTargetApi api, string flow
|
||||
where flow = captureFlow(api)
|
||||
select flow order by flow
|
||||
|
||||
@@ -29,17 +29,23 @@ private class ReturnNodeExt extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
class DataFlowTargetApi extends TargetApiSpecific {
|
||||
DataFlowTargetApi() { not isUninterestingForDataFlowModels(this) }
|
||||
class DataFlowSummaryTargetApi extends SummaryTargetApi {
|
||||
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
|
||||
}
|
||||
|
||||
private module Printing implements PrintingSig {
|
||||
class Api = DataFlowTargetApi;
|
||||
class DataFlowSourceTargetApi = SourceTargetApi;
|
||||
|
||||
class DataFlowSinkTargetApi = SinkTargetApi;
|
||||
|
||||
private module ModelPrintingInput implements ModelPrintingSig {
|
||||
class SummaryApi = DataFlowSummaryTargetApi;
|
||||
|
||||
class SourceOrSinkApi = SourceOrSinkTargetApi;
|
||||
|
||||
string getProvenance() { result = "df-generated" }
|
||||
}
|
||||
|
||||
module ModelPrinting = PrintingImpl<Printing>;
|
||||
module Printing = ModelPrinting<ModelPrintingInput>;
|
||||
|
||||
/**
|
||||
* Holds if `c` is a relevant content kind, where the underlying type is relevant.
|
||||
@@ -89,12 +95,12 @@ string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific
|
||||
/**
|
||||
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
|
||||
*/
|
||||
string captureQualifierFlow(TargetApiSpecific api) {
|
||||
string captureQualifierFlow(DataFlowSummaryTargetApi api) {
|
||||
exists(ReturnNodeExt ret |
|
||||
api = returnNodeEnclosingCallable(ret) and
|
||||
isOwnInstanceAccessNode(ret)
|
||||
) and
|
||||
result = ModelPrinting::asValueModel(api, qualifierString(), "ReturnValue")
|
||||
result = Printing::asValueModel(api, qualifierString(), "ReturnValue")
|
||||
}
|
||||
|
||||
private int accessPathLimit0() { result = 2 }
|
||||
@@ -145,12 +151,12 @@ private class TaintStore extends TaintState, TTaintStore {
|
||||
*
|
||||
* This can be used to generate Flow summaries for APIs from parameter to return.
|
||||
*/
|
||||
module ThroughFlowConfig implements DataFlow::StateConfigSig {
|
||||
module PropagateFlowConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = TaintState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof DataFlow::ParameterNode and
|
||||
source.getEnclosingCallable() instanceof DataFlowTargetApi and
|
||||
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi and
|
||||
state.(TaintRead).getStep() = 0
|
||||
}
|
||||
|
||||
@@ -190,19 +196,19 @@ module ThroughFlowConfig implements DataFlow::StateConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
private module ThroughFlow = TaintTracking::GlobalWithState<ThroughFlowConfig>;
|
||||
private module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfig>;
|
||||
|
||||
/**
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
|
||||
*/
|
||||
string captureThroughFlow(DataFlowTargetApi api) {
|
||||
string captureThroughFlow(DataFlowSummaryTargetApi api) {
|
||||
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output |
|
||||
ThroughFlow::flow(p, returnNodeExt) and
|
||||
PropagateFlow::flow(p, returnNodeExt) and
|
||||
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
|
||||
input = parameterNodeAsInput(p) and
|
||||
output = returnNodeExt.getOutput() and
|
||||
input != output and
|
||||
result = ModelPrinting::asTaintModel(api, input, output)
|
||||
result = Printing::asTaintModel(api, input, output)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -213,35 +219,42 @@ string captureThroughFlow(DataFlowTargetApi api) {
|
||||
* This can be used to generate Source summaries for an API, if the API expose an already known source
|
||||
* via its return (then the API itself becomes a source).
|
||||
*/
|
||||
module FromSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlowTargetApi c |
|
||||
sink instanceof ReturnNodeExt and
|
||||
sink.getEnclosingCallable() = c
|
||||
module PropagateFromSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(string kind |
|
||||
isRelevantSourceKind(kind) and
|
||||
ExternalFlow::sourceNode(source, kind)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof ReturnNodeExt and
|
||||
sink.getEnclosingCallable() instanceof DataFlowSourceTargetApi
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSinkCallContext }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
exists(Type t | t = n.getType() and not isRelevantType(t))
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
isRelevantTaintStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
private module FromSource = TaintTracking::Global<FromSourceConfig>;
|
||||
private module PropagateFromSource = TaintTracking::Global<PropagateFromSourceConfig>;
|
||||
|
||||
/**
|
||||
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
|
||||
*/
|
||||
string captureSource(DataFlowTargetApi api) {
|
||||
string captureSource(DataFlowSourceTargetApi api) {
|
||||
exists(DataFlow::Node source, ReturnNodeExt sink, string kind |
|
||||
FromSource::flow(source, sink) and
|
||||
PropagateFromSource::flow(source, sink) and
|
||||
ExternalFlow::sourceNode(source, kind) and
|
||||
api = sink.getEnclosingCallable() and
|
||||
isRelevantSourceKind(kind) and
|
||||
result = ModelPrinting::asSourceModel(api, sink.getOutput(), kind)
|
||||
not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and
|
||||
result = Printing::asSourceModel(api, sink.getOutput(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -253,11 +266,19 @@ string captureSource(DataFlowTargetApi api) {
|
||||
* into an existing known sink (then the API itself becomes a sink).
|
||||
*/
|
||||
module PropagateToSinkConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { apiSource(source) }
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
apiSource(source) and source.getEnclosingCallable() instanceof DataFlowSinkTargetApi
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { ExternalFlow::sinkNode(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(string kind | isRelevantSinkKind(kind) and ExternalFlow::sinkNode(sink, kind))
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { sinkModelSanitizer(node) }
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(Type t | t = node.getType() and not isRelevantType(t))
|
||||
or
|
||||
sinkModelSanitizer(node)
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
|
||||
|
||||
@@ -271,12 +292,11 @@ private module PropagateToSink = TaintTracking::Global<PropagateToSinkConfig>;
|
||||
/**
|
||||
* Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink.
|
||||
*/
|
||||
string captureSink(DataFlowTargetApi api) {
|
||||
string captureSink(DataFlowSinkTargetApi api) {
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, string kind |
|
||||
PropagateToSink::flow(src, sink) and
|
||||
ExternalFlow::sinkNode(sink, kind) and
|
||||
api = src.getEnclosingCallable() and
|
||||
isRelevantSinkKind(kind) and
|
||||
result = ModelPrinting::asSinkModel(api, asInputArgument(src), kind)
|
||||
result = Printing::asSinkModel(api, asInputArgument(src), kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,72 +1,11 @@
|
||||
private import CaptureModelsSpecific
|
||||
private import java as J
|
||||
private import codeql.mad.modelgenerator.ModelPrinting
|
||||
private import CaptureModelsSpecific as Specific
|
||||
|
||||
signature module PrintingSig {
|
||||
/**
|
||||
* The class of APIs relevant for model generation.
|
||||
*/
|
||||
class Api extends TargetApiSpecific;
|
||||
private module ModelPrintingLang implements ModelPrintingLangSig {
|
||||
class Callable = J::Callable;
|
||||
|
||||
/**
|
||||
* Gets the string representation of the provenance of the models.
|
||||
*/
|
||||
string getProvenance();
|
||||
predicate partialModel = Specific::partialModel/6;
|
||||
}
|
||||
|
||||
module PrintingImpl<PrintingSig Printing> {
|
||||
/**
|
||||
* Gets the summary model for `api` with `input`, `output` and `kind`.
|
||||
*/
|
||||
bindingset[input, output, kind]
|
||||
private string asSummaryModel(Printing::Api api, string input, string output, string kind) {
|
||||
result =
|
||||
asPartialModel(api) + input + ";" //
|
||||
+ output + ";" //
|
||||
+ kind + ";" //
|
||||
+ Printing::getProvenance()
|
||||
}
|
||||
|
||||
string asNeutralSummaryModel(Printing::Api api) {
|
||||
result =
|
||||
asPartialNeutralModel(api) //
|
||||
+ "summary" + ";" //
|
||||
+ Printing::getProvenance()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
string asValueModel(Printing::Api api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "value")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the taint summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
string asTaintModel(Printing::Api api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "taint")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sink model for `api` with `input` and `kind`.
|
||||
*/
|
||||
bindingset[input, kind]
|
||||
string asSinkModel(Printing::Api api, string input, string kind) {
|
||||
result =
|
||||
asPartialModel(api) + input + ";" //
|
||||
+ kind + ";" //
|
||||
+ Printing::getProvenance()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source model for `api` with `output` and `kind`.
|
||||
*/
|
||||
bindingset[output, kind]
|
||||
string asSourceModel(Printing::Api api, string output, string kind) {
|
||||
result =
|
||||
asPartialModel(api) + output + ";" //
|
||||
+ kind + ";" //
|
||||
+ Printing::getProvenance()
|
||||
}
|
||||
}
|
||||
import ModelPrintingImpl<ModelPrintingLang>
|
||||
|
||||
@@ -58,11 +58,21 @@ private J::Callable liftedImpl(J::Callable m) {
|
||||
not exists(getARelevantOverride(result))
|
||||
}
|
||||
|
||||
private predicate hasManualModel(Callable api) {
|
||||
private predicate hasManualSummaryModel(Callable api) {
|
||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()).asCallable() or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()).asCallable()
|
||||
}
|
||||
|
||||
private predicate hasManualSourceModel(Callable api) {
|
||||
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel()).asCallable()
|
||||
}
|
||||
|
||||
private predicate hasManualSinkModel(Callable api) {
|
||||
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
|
||||
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel()).asCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is irrelevant to generate models for `api` based on data flow analysis.
|
||||
*
|
||||
@@ -72,6 +82,28 @@ predicate isUninterestingForDataFlowModels(Callable api) {
|
||||
api.getDeclaringType() instanceof J::Interface and not exists(api.getBody())
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating source or
|
||||
* sink models.
|
||||
*/
|
||||
class SourceOrSinkTargetApi extends Callable {
|
||||
SourceOrSinkTargetApi() { relevant(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating sink models.
|
||||
*/
|
||||
class SinkTargetApi extends SourceOrSinkTargetApi {
|
||||
SinkTargetApi() { not hasManualSinkModel(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating source models.
|
||||
*/
|
||||
class SourceTargetApi extends SourceOrSinkTargetApi {
|
||||
SourceTargetApi() { not hasManualSourceModel(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is irrelevant to generate models for `api` based on type-based analysis.
|
||||
*
|
||||
@@ -80,18 +112,18 @@ predicate isUninterestingForDataFlowModels(Callable api) {
|
||||
predicate isUninterestingForTypeBasedFlowModels(Callable api) { none() }
|
||||
|
||||
/**
|
||||
* A class of callables that are potentially relevant for generating summary, source, sink
|
||||
* and neutral models.
|
||||
* A class of callables that are potentially relevant for generating summary or
|
||||
* neutral models.
|
||||
*
|
||||
* In the Standard library and 3rd party libraries it is the callables (or callables that have a
|
||||
* super implementation) that can be called from outside the library itself.
|
||||
*/
|
||||
class TargetApiSpecific extends Callable {
|
||||
class SummaryTargetApi extends Callable {
|
||||
private Callable lift;
|
||||
|
||||
TargetApiSpecific() {
|
||||
SummaryTargetApi() {
|
||||
lift = liftedImpl(this) and
|
||||
not hasManualModel(lift)
|
||||
not hasManualSummaryModel(lift)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,53 +142,25 @@ private string isExtensible(Callable c) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate type name for the model.
|
||||
* Holds if the callable `c` is in package `package`
|
||||
* and is a member of `type`.
|
||||
*/
|
||||
private string typeAsModel(Callable c) {
|
||||
exists(RefType type | type = c.getDeclaringType() |
|
||||
result =
|
||||
type.getCompilationUnit().getPackage().getName() + ";" +
|
||||
type.getErasure().(J::RefType).nestedName()
|
||||
private predicate qualifiedName(Callable c, string package, string type) {
|
||||
exists(RefType t | t = c.getDeclaringType() |
|
||||
package = t.getCompilationUnit().getPackage().getName() and
|
||||
type = t.getErasure().(J::RefType).nestedName()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate partialModel(
|
||||
Callable api, string type, string extensible, string name, string parameters
|
||||
predicate partialModel(
|
||||
Callable api, string package, string type, string extensible, string name, string parameters
|
||||
) {
|
||||
type = typeAsModel(api) and
|
||||
qualifiedName(api, package, type) and
|
||||
extensible = isExtensible(api) and
|
||||
name = api.getName() and
|
||||
parameters = ExternalFlow::paramsString(api)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the first 6 columns for MaD rows.
|
||||
*/
|
||||
string asPartialModel(TargetApiSpecific api) {
|
||||
exists(string type, string extensible, string name, string parameters |
|
||||
partialModel(api.lift(), type, extensible, name, parameters) and
|
||||
result =
|
||||
type + ";" //
|
||||
+ extensible + ";" //
|
||||
+ name + ";" //
|
||||
+ parameters + ";" //
|
||||
+ /* ext + */ ";" //
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the first 4 columns for neutral MaD rows.
|
||||
*/
|
||||
string asPartialNeutralModel(TargetApiSpecific api) {
|
||||
exists(string type, string name, string parameters |
|
||||
partialModel(api, type, _, name, parameters) and
|
||||
result =
|
||||
type + ";" //
|
||||
+ name + ";" //
|
||||
+ parameters + ";" //
|
||||
)
|
||||
}
|
||||
|
||||
predicate isPrimitiveTypeUsedForBulkData(J::Type t) {
|
||||
t.hasName(["byte", "char", "Byte", "Character"])
|
||||
}
|
||||
@@ -250,15 +254,6 @@ predicate sinkModelSanitizer(DataFlow::Node node) {
|
||||
)
|
||||
}
|
||||
|
||||
private class ManualNeutralSinkCallable extends Callable {
|
||||
ManualNeutralSinkCallable() {
|
||||
this =
|
||||
any(FlowSummaryImpl::Public::NeutralCallable nc |
|
||||
nc.hasManualModel() and nc.getKind() = "sink"
|
||||
).asCallable()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `source` is an api entrypoint relevant for creating sink models.
|
||||
*/
|
||||
@@ -267,17 +262,19 @@ predicate apiSource(DataFlow::Node source) {
|
||||
source.asExpr().(J::FieldAccess).isOwnFieldAccess() or
|
||||
source instanceof DataFlow::ParameterNode
|
||||
) and
|
||||
exists(Callable enclosing | enclosing = source.getEnclosingCallable() |
|
||||
exists(liftedImpl(enclosing)) and
|
||||
not enclosing instanceof ManualNeutralSinkCallable and
|
||||
exists(J::RefType t |
|
||||
t = enclosing.getDeclaringType().getAnAncestor() and
|
||||
not t instanceof J::TypeObject and
|
||||
t.isPublic()
|
||||
)
|
||||
exists(J::RefType t |
|
||||
t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and
|
||||
not t instanceof J::TypeObject and
|
||||
t.isPublic()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is not relevant to generate a source model for `api`, even
|
||||
* if flow is detected from a node within `source` to a sink within `api`.
|
||||
*/
|
||||
predicate irrelevantSourceSinkApi(Callable source, SourceTargetApi api) { none() }
|
||||
|
||||
/**
|
||||
* Gets the MaD input string representation of `source`.
|
||||
*/
|
||||
|
||||
@@ -67,7 +67,7 @@ private import CaptureModels
|
||||
* Captured Model:
|
||||
* ```p;Foo;true;addToList;;Argument[0];Argument[1];taint;df-generated```
|
||||
*/
|
||||
string captureFlow(DataFlowTargetApi api) {
|
||||
string captureFlow(DataFlowSummaryTargetApi api) {
|
||||
result = captureQualifierFlow(api) or
|
||||
result = captureThroughFlow(api)
|
||||
}
|
||||
@@ -77,8 +77,8 @@ string captureFlow(DataFlowTargetApi api) {
|
||||
* A neutral summary model is generated, if we are not generating
|
||||
* a summary model that applies to `api`.
|
||||
*/
|
||||
string captureNoFlow(DataFlowTargetApi api) {
|
||||
not exists(DataFlowTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and
|
||||
string captureNoFlow(DataFlowSummaryTargetApi api) {
|
||||
not exists(DataFlowSummaryTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and
|
||||
api.isRelevant() and
|
||||
result = ModelPrinting::asNeutralSummaryModel(api)
|
||||
result = Printing::asNeutralSummaryModel(api)
|
||||
}
|
||||
|
||||
@@ -283,19 +283,21 @@ private predicate output(Callable callable, TypeVariable tv, string output) {
|
||||
functionalSink(callable, tv, output)
|
||||
}
|
||||
|
||||
module Printing implements PrintingSig {
|
||||
class Api = TypeBasedFlowTargetApi;
|
||||
module ModelPrintingInput implements ModelPrintingSig {
|
||||
class SummaryApi = TypeBasedFlowTargetApi;
|
||||
|
||||
class SourceOrSinkApi = Specific::SourceOrSinkTargetApi;
|
||||
|
||||
string getProvenance() { result = "tb-generated" }
|
||||
}
|
||||
|
||||
private module ModelPrinting = PrintingImpl<Printing>;
|
||||
private module Printing = ModelPrinting<ModelPrintingInput>;
|
||||
|
||||
/**
|
||||
* A class of callables that are relevant generating summaries for based
|
||||
* on the Theorems for Free approach.
|
||||
*/
|
||||
class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific {
|
||||
class TypeBasedFlowTargetApi extends Specific::SummaryTargetApi {
|
||||
TypeBasedFlowTargetApi() { not Specific::isUninterestingForTypeBasedFlowModels(this) }
|
||||
|
||||
/**
|
||||
@@ -327,7 +329,7 @@ class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific {
|
||||
output(this, tv, output) and
|
||||
input != output
|
||||
|
|
||||
result = ModelPrinting::asValueModel(this, input, output)
|
||||
result = Printing::asValueModel(this, input, output)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user