mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge branch 'main' into atorralba/android_slice_models
This commit is contained in:
@@ -52,6 +52,6 @@ predicate hasSmapLocationInfo(
|
||||
smap(inputFile, isl, outputFile, osl) and
|
||||
smap(inputFile, iel - 1, outputFile, oel) and
|
||||
isc = 1 and
|
||||
iec = 0
|
||||
iec = 1
|
||||
)
|
||||
}
|
||||
|
||||
@@ -156,6 +156,11 @@ class TypeObjectOutputStream extends RefType {
|
||||
TypeObjectOutputStream() { hasQualifiedName("java.io", "ObjectOutputStream") }
|
||||
}
|
||||
|
||||
/** The type `java.io.ObjectInputStream`. */
|
||||
class TypeObjectInputStream extends RefType {
|
||||
TypeObjectInputStream() { hasQualifiedName("java.io", "ObjectInputStream") }
|
||||
}
|
||||
|
||||
/** The class `java.nio.file.Paths`. */
|
||||
class TypePaths extends Class {
|
||||
TypePaths() { this.hasQualifiedName("java.nio.file", "Paths") }
|
||||
@@ -275,7 +280,7 @@ class WriteObjectMethod extends Method {
|
||||
*/
|
||||
class ReadObjectMethod extends Method {
|
||||
ReadObjectMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
this.getDeclaringType() instanceof TypeObjectInputStream and
|
||||
(
|
||||
this.hasName("readObject") or
|
||||
this.hasName("readObjectOverride") or
|
||||
|
||||
@@ -77,8 +77,9 @@ private import FlowSummary
|
||||
*/
|
||||
private module Frameworks {
|
||||
private import internal.ContainerFlow
|
||||
private import semmle.code.java.frameworks.android.XssSinks
|
||||
private import semmle.code.java.frameworks.android.Android
|
||||
private import semmle.code.java.frameworks.android.Intent
|
||||
private import semmle.code.java.frameworks.android.XssSinks
|
||||
private import semmle.code.java.frameworks.ApacheHttp
|
||||
private import semmle.code.java.frameworks.apache.Collections
|
||||
private import semmle.code.java.frameworks.apache.Lang
|
||||
@@ -92,6 +93,7 @@ private module Frameworks {
|
||||
private import semmle.code.java.frameworks.JsonJava
|
||||
private import semmle.code.java.frameworks.Objects
|
||||
private import semmle.code.java.frameworks.Optional
|
||||
private import semmle.code.java.frameworks.Stream
|
||||
private import semmle.code.java.frameworks.Strings
|
||||
private import semmle.code.java.frameworks.spring.SpringCache
|
||||
private import semmle.code.java.frameworks.spring.SpringHttp
|
||||
@@ -575,7 +577,7 @@ module CsvValidation {
|
||||
not (part = "Argument" and pred = "sink") and
|
||||
not parseArg(part, _)
|
||||
or
|
||||
specSplit(input, part, _) and
|
||||
part = specLast(input) and
|
||||
parseParam(part, _)
|
||||
) and
|
||||
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
|
||||
|
||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||
) and
|
||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||
apLimit < tails and
|
||||
tupleLimit < (tails - 1) * nodes
|
||||
tupleLimit < (tails - 1) * nodes and
|
||||
not tc.forceHighPrecision()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
if apa.getHead().forceHighPrecision()
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||
) and
|
||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||
apLimit < tails and
|
||||
tupleLimit < (tails - 1) * nodes
|
||||
tupleLimit < (tails - 1) * nodes and
|
||||
not tc.forceHighPrecision()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
if apa.getHead().forceHighPrecision()
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||
) and
|
||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||
apLimit < tails and
|
||||
tupleLimit < (tails - 1) * nodes
|
||||
tupleLimit < (tails - 1) * nodes and
|
||||
not tc.forceHighPrecision()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
if apa.getHead().forceHighPrecision()
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||
) and
|
||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||
apLimit < tails and
|
||||
tupleLimit < (tails - 1) * nodes
|
||||
tupleLimit < (tails - 1) * nodes and
|
||||
not tc.forceHighPrecision()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
if apa.getHead().forceHighPrecision()
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||
) and
|
||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||
apLimit < tails and
|
||||
tupleLimit < (tails - 1) * nodes
|
||||
tupleLimit < (tails - 1) * nodes and
|
||||
not tc.forceHighPrecision()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
if apa.getHead().forceHighPrecision()
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||
) and
|
||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||
apLimit < tails and
|
||||
tupleLimit < (tails - 1) * nodes
|
||||
tupleLimit < (tails - 1) * nodes and
|
||||
not tc.forceHighPrecision()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
if apa.getHead().forceHighPrecision()
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -937,7 +937,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
recordDataFlowCallSite(this.getCall(), callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
||||
@@ -1236,6 +1236,13 @@ class TypedContent extends MkTypedContent {
|
||||
|
||||
/** Gets a textual representation of this content. */
|
||||
string toString() { result = c.toString() }
|
||||
|
||||
/**
|
||||
* Holds if access paths with this `TypedContent` at their head always should
|
||||
* be tracked at high precision. This disables adaptive access path precision
|
||||
* for such access paths.
|
||||
*/
|
||||
predicate forceHighPrecision() { forceHighPrecision(c) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1250,7 +1257,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||
) and
|
||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||
apLimit < tails and
|
||||
tupleLimit < (tails - 1) * nodes
|
||||
tupleLimit < (tails - 1) * nodes and
|
||||
not tc.forceHighPrecision()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
if apa.getHead().forceHighPrecision()
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
aps = countPotentialAps(apa, config) and
|
||||
nodes = countNodesUsingAccessPath(apa, config) and
|
||||
accessPathCostLimits(apLimit, tupleLimit) and
|
||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -234,6 +234,19 @@ class DataFlowCall extends TDataFlowCall {
|
||||
|
||||
/** Gets the location of this call. */
|
||||
abstract Location getLocation();
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
/** A source call, that is, a `Call`. */
|
||||
@@ -308,6 +321,14 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
/**
|
||||
* Holds if access paths with `c` at their head always should be tracked at high
|
||||
* precision. This disables adaptive access path precision for such access paths.
|
||||
*/
|
||||
predicate forceHighPrecision(Content c) {
|
||||
c instanceof ArrayContent or c instanceof CollectionContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
|
||||
* modified or its modification cannot be observed, for example if it is a
|
||||
|
||||
@@ -870,4 +870,95 @@ module Private {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides query predicates for rendering the generated data flow graph for
|
||||
* a summarized callable.
|
||||
*
|
||||
* Import this module into a `.ql` file of `@kind graph` to render the graph.
|
||||
* The graph is restricted to callables from `RelevantSummarizedCallable`.
|
||||
*/
|
||||
module RenderSummarizedCallable {
|
||||
/** A summarized callable to include in the graph. */
|
||||
abstract class RelevantSummarizedCallable extends SummarizedCallable { }
|
||||
|
||||
private newtype TNodeOrCall =
|
||||
MkNode(Node n) {
|
||||
exists(RelevantSummarizedCallable c |
|
||||
n = summaryNode(c, _)
|
||||
or
|
||||
n.(ParamNode).isParameterOf(c, _)
|
||||
)
|
||||
} or
|
||||
MkCall(DataFlowCall call) {
|
||||
call = summaryDataFlowCall(_) and
|
||||
call.getEnclosingCallable() instanceof RelevantSummarizedCallable
|
||||
}
|
||||
|
||||
private class NodeOrCall extends TNodeOrCall {
|
||||
Node asNode() { this = MkNode(result) }
|
||||
|
||||
DataFlowCall asCall() { this = MkCall(result) }
|
||||
|
||||
string toString() {
|
||||
result = this.asNode().toString()
|
||||
or
|
||||
result = this.asCall().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
or
|
||||
this.asCall().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate nodes(NodeOrCall n, string key, string val) {
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
private predicate edgesComponent(NodeOrCall a, NodeOrCall b, string value) {
|
||||
exists(boolean preservesValue |
|
||||
Private::Steps::summaryLocalStep(a.asNode(), b.asNode(), preservesValue) and
|
||||
if preservesValue = true then value = "value" else value = "taint"
|
||||
)
|
||||
or
|
||||
exists(Content c |
|
||||
Private::Steps::summaryReadStep(a.asNode(), c, b.asNode()) and
|
||||
value = "read (" + c + ")"
|
||||
or
|
||||
Private::Steps::summaryStoreStep(a.asNode(), c, b.asNode()) and
|
||||
value = "store (" + c + ")"
|
||||
or
|
||||
Private::Steps::summaryClearsContent(a.asNode(), c) and
|
||||
b = a and
|
||||
value = "clear (" + c + ")"
|
||||
)
|
||||
or
|
||||
summaryPostUpdateNode(b.asNode(), a.asNode()) and
|
||||
value = "post-update"
|
||||
or
|
||||
b.asCall() = summaryDataFlowCall(a.asNode()) and
|
||||
value = "receiver"
|
||||
or
|
||||
exists(int i |
|
||||
summaryArgumentNode(b.asCall(), a.asNode(), i) and
|
||||
value = "argument (" + i + ")"
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(NodeOrCall a, NodeOrCall b, string key, string value) {
|
||||
key = "semmle.label" and
|
||||
value = strictconcat(string s | edgesComponent(a, b, s) | s, " / ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ private predicate taintPreservingQualifierToMethod(Method m) {
|
||||
m.getName() = "toString"
|
||||
)
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
m.getDeclaringType() instanceof TypeObjectInputStream and
|
||||
m.getName().matches("read%")
|
||||
or
|
||||
m instanceof GetterMethod and
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
* Provides Java-specific definitions for use in sign analysis.
|
||||
*/
|
||||
module Private {
|
||||
private import java as J
|
||||
import semmle.code.java.dataflow.RangeUtils as RU
|
||||
private import semmle.code.java.dataflow.SSA as Ssa
|
||||
private import semmle.code.java.controlflow.Guards as G
|
||||
private import java as J
|
||||
private import Sign
|
||||
import Impl
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class SsaReadPositionBlock extends SsaReadPosition, TSsaReadPositionBlock {
|
||||
/** Gets the basic block corresponding to this position. */
|
||||
BasicBlock getBlock() { this = TSsaReadPositionBlock(result) }
|
||||
|
||||
override predicate hasReadOfVar(SsaVariable v) { getBlock() = getAReadBasicBlock(v) }
|
||||
override predicate hasReadOfVar(SsaVariable v) { this.getBlock() = getAReadBasicBlock(v) }
|
||||
|
||||
override string toString() { result = "block" }
|
||||
}
|
||||
@@ -49,8 +49,8 @@ class SsaReadPositionPhiInputEdge extends SsaReadPosition, TSsaReadPositionPhiIn
|
||||
|
||||
/** Holds if `inp` is an input to `phi` along this edge. */
|
||||
predicate phiInput(SsaPhiNode phi, SsaVariable inp) {
|
||||
phi.hasInputFromBlock(inp, getOrigBlock()) and
|
||||
getPhiBlock() = phi.getBasicBlock()
|
||||
phi.hasInputFromBlock(inp, this.getOrigBlock()) and
|
||||
this.getPhiBlock() = phi.getBasicBlock()
|
||||
}
|
||||
|
||||
override string toString() { result = "edge" }
|
||||
|
||||
@@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
isSanitizer(node) or
|
||||
this.isSanitizer(node) or
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
@@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
isAdditionalTaintStep(node1, node2) or
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
|
||||
@@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
isSanitizer(node) or
|
||||
this.isSanitizer(node) or
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
this.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
@@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
isAdditionalTaintStep(node1, node2) or
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,5 +14,5 @@ class RemoteCallableMethod extends Method {
|
||||
private predicate remoteCallableMethod(Method method) {
|
||||
method.getDeclaringType().getASupertype() instanceof TypeRemote
|
||||
or
|
||||
exists(Method meth | remoteCallableMethod(meth) and method.getAnOverride() = meth)
|
||||
exists(Method meth | remoteCallableMethod(meth) and method.overrides(meth))
|
||||
}
|
||||
|
||||
95
java/ql/lib/semmle/code/java/frameworks/Stream.qll
Normal file
95
java/ql/lib/semmle/code/java/frameworks/Stream.qll
Normal file
@@ -0,0 +1,95 @@
|
||||
/** Definitions related to `java.util.stream`. */
|
||||
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
private class StreamModel extends SummaryModelCsv {
|
||||
override predicate row(string s) {
|
||||
s =
|
||||
[
|
||||
"java.util.stream;BaseStream;true;iterator;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;BaseStream;true;onClose;(Runnable);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;BaseStream;true;parallel;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;BaseStream;true;sequential;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;BaseStream;true;spliterator;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;BaseStream;true;unordered;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;allMatch;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;anyMatch;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;ReturnValue of Argument[0];Parameter[0] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Parameter[0] of Argument[1];ReturnValue;value",
|
||||
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Parameter[0] of Argument[1];Parameter[0..1] of Argument[2];value",
|
||||
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Parameter[0..1] of Argument[2];Parameter[0] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;collect;(Supplier,BiConsumer,BiConsumer);;Element of Argument[-1];Parameter[1] of Argument[1];value",
|
||||
// Missing: collect(Collector<T,A,R> collector)
|
||||
"java.util.stream;Stream;true;concat;(Stream,Stream);;Element of Argument[0..1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;distinct;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;dropWhile;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;dropWhile;(Predicate);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;filter;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;filter;(Predicate);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;findAny;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;findFirst;();;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;flatMap;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;flatMap;(Function);;Element of ReturnValue of Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;flatMapToDouble;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;flatMapToInt;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;flatMapToLong;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;forEach;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;forEachOrdered;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;generate;(Supplier);;ReturnValue of Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;Argument[0];Parameter[0] of Argument[1..2];value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;ReturnValue of Argument[2];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,Predicate,UnaryOperator);;ReturnValue of Argument[2];Parameter[0] of Argument[1..2];value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;Argument[0];Parameter[0] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;ReturnValue of Argument[1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;iterate;(Object,UnaryOperator);;ReturnValue of Argument[1];Parameter[0] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;limit;(long);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;map;(Function);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;map;(Function);;ReturnValue of Argument[0];Element of ReturnValue;value",
|
||||
// Missing for mapMulti(BiConsumer) (not currently supported):
|
||||
// Argument[0] of Parameter[1] of Argument[0] -> Element of Parameter[1] of Argument[0]
|
||||
// Element of Parameter[1] of Argument[0] -> Element of ReturnValue
|
||||
"java.util.stream;Stream;true;mapMulti;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;mapMultiToDouble;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;mapMultiToInt;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;mapMultiToLong;(BiConsumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;mapToDouble;(ToDoubleFunction);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;mapToInt;(ToIntFunction);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;mapToLong;(ToLongFunction);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;max;(Comparator);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;max;(Comparator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;min;(Comparator);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;min;(Comparator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;noneMatch;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;of;(Object);;Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;of;(Object[]);;ArrayElement of Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;ofNullable;(Object);;Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;peek;(Consumer);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;peek;(Consumer);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;reduce;(BinaryOperator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;reduce;(BinaryOperator);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;reduce;(BinaryOperator);;ReturnValue of Argument[0];Parameter[0..1] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;reduce;(BinaryOperator);;ReturnValue of Argument[0];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;Element of Argument[-1];Parameter[0..1] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;Argument[0];Parameter[0..1] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;Argument[0];ReturnValue;value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;ReturnValue of Argument[1];Parameter[0..1] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BinaryOperator);;ReturnValue of Argument[1];ReturnValue;value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Element of Argument[-1];Parameter[1] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];Parameter[0] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];Parameter[0..1] of Argument[2];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];ReturnValue;value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;ReturnValue of Argument[1..2];Parameter[0] of Argument[1];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;ReturnValue of Argument[1..2];Parameter[0..1] of Argument[2];value",
|
||||
"java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;ReturnValue of Argument[1..2];ReturnValue;value",
|
||||
"java.util.stream;Stream;true;skip;(long);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;sorted;;;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;sorted;(Comparator);;Element of Argument[-1];Parameter[0..1] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;takeWhile;(Predicate);;Element of Argument[-1];Parameter[0] of Argument[0];value",
|
||||
"java.util.stream;Stream;true;takeWhile;(Predicate);;Element of Argument[-1];Element of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;toArray;;;Element of Argument[-1];ArrayElement of ReturnValue;value",
|
||||
"java.util.stream;Stream;true;toList;();;Element of Argument[-1];Element of ReturnValue;value"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -202,3 +202,44 @@ private class ContentProviderSourceModels extends SourceModelCsv {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** Interface for classes whose instances can be written to and restored from a Parcel. */
|
||||
class TypeParcelable extends Interface {
|
||||
TypeParcelable() { this.hasQualifiedName("android.os", "Parcelable") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that overrides `android.os.Parcelable.Creator.createFromParcel`.
|
||||
*/
|
||||
class CreateFromParcelMethod extends Method {
|
||||
CreateFromParcelMethod() {
|
||||
this.hasName("createFromParcel") and
|
||||
this.getEnclosingCallable().getDeclaringType().getASupertype*() instanceof TypeParcelable
|
||||
}
|
||||
}
|
||||
|
||||
private class ParcelPropagationModels extends SummaryModelCsv {
|
||||
override predicate row(string s) {
|
||||
// Parcel readers that return their value
|
||||
s =
|
||||
"android.os;Parcel;false;read" +
|
||||
[
|
||||
"Array", "ArrayList", "Boolean", "Bundle", "Byte", "Double", "FileDescriptor", "Float",
|
||||
"HashMap", "Int", "Long", "Parcelable", "ParcelableArray", "PersistableBundle",
|
||||
"Serializable", "Size", "SizeF", "SparseArray", "SparseBooleanArray", "String",
|
||||
"StrongBinder", "TypedObject", "Value"
|
||||
] + ";;;Argument[-1];ReturnValue;taint"
|
||||
or
|
||||
// Parcel readers that write to an existing object
|
||||
s =
|
||||
"android.os;Parcel;false;read" +
|
||||
[
|
||||
"BinderArray", "BinderList", "BooleanArray", "ByteArray", "CharArray", "DoubleArray",
|
||||
"FloatArray", "IntArray", "List", "LongArray", "Map", "ParcelableList", "StringArray",
|
||||
"StringList", "TypedArray", "TypedList"
|
||||
] + ";;;Argument[-1];Argument[0];taint"
|
||||
or
|
||||
// One Parcel method that aliases an argument to a return value
|
||||
s = "android.os;Parcel;false;readParcelableList;;;Argument[0];ReturnValue;value"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,32 +3,53 @@ private import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.FlowSteps
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/**
|
||||
* The class `android.content.Intent`.
|
||||
*/
|
||||
class TypeIntent extends Class {
|
||||
TypeIntent() { hasQualifiedName("android.content", "Intent") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.app.Activity`.
|
||||
*/
|
||||
class TypeActivity extends Class {
|
||||
TypeActivity() { hasQualifiedName("android.app", "Activity") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.content.Context`.
|
||||
*/
|
||||
class TypeContext extends RefType {
|
||||
TypeContext() { hasQualifiedName("android.content", "Context") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `android.content.BroadcastReceiver`.
|
||||
*/
|
||||
class TypeBroadcastReceiver extends Class {
|
||||
TypeBroadcastReceiver() { hasQualifiedName("android.content", "BroadcastReceiver") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Activity.getIntent`
|
||||
*/
|
||||
class AndroidGetIntentMethod extends Method {
|
||||
AndroidGetIntentMethod() { hasName("getIntent") and getDeclaringType() instanceof TypeActivity }
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `BroadcastReceiver.onReceive`.
|
||||
*/
|
||||
class AndroidReceiveIntentMethod extends Method {
|
||||
AndroidReceiveIntentMethod() {
|
||||
hasName("onReceive") and getDeclaringType() instanceof TypeBroadcastReceiver
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Context.startActivity` or `startActivities`.
|
||||
*/
|
||||
class ContextStartActivityMethod extends Method {
|
||||
ContextStartActivityMethod() {
|
||||
(hasName("startActivity") or hasName("startActivities")) and
|
||||
@@ -44,6 +65,16 @@ private class IntentFieldsInheritTaint extends DataFlow::SyntheticFieldContent,
|
||||
IntentFieldsInheritTaint() { this.getField().matches("android.content.Intent.%") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Intent.getParcelableExtra`.
|
||||
*/
|
||||
class IntentGetParcelableExtraMethod extends Method {
|
||||
IntentGetParcelableExtraMethod() {
|
||||
hasName("getParcelableExtra") and
|
||||
getDeclaringType() instanceof TypeIntent
|
||||
}
|
||||
}
|
||||
|
||||
private class IntentBundleFlowSteps extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
|
||||
@@ -37,7 +37,7 @@ predicate isGigaSpacesEventMethod(Method eventMethod) {
|
||||
class GigaSpacesSpaceIdGetterMethod extends Method {
|
||||
GigaSpacesSpaceIdGetterMethod() {
|
||||
getAnAnnotation().getType().hasQualifiedName("com.gigaspaces.annotation.pojo", "SpaceId") and
|
||||
getName().prefix(3) = "get"
|
||||
getName().matches("get%")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class GigaSpacesSpaceIdSetterMethod extends Method {
|
||||
GigaSpacesSpaceIdSetterMethod() {
|
||||
exists(GigaSpacesSpaceIdGetterMethod getterMethod |
|
||||
getterMethod.getDeclaringType() = getDeclaringType() and
|
||||
getName().prefix(3) = "set"
|
||||
getName().matches("set%")
|
||||
|
|
||||
getterMethod.getName().suffix(3) = getName().suffix(3)
|
||||
)
|
||||
@@ -62,6 +62,6 @@ class GigaSpacesSpaceIdSetterMethod extends Method {
|
||||
class GigaSpacesSpaceRoutingMethod extends Method {
|
||||
GigaSpacesSpaceRoutingMethod() {
|
||||
getAnAnnotation().getType().hasQualifiedName("com.gigaspaces.annotation.pojo", "SpaceRouting") and
|
||||
getName().prefix(3) = "get"
|
||||
getName().matches("get%")
|
||||
}
|
||||
}
|
||||
|
||||
36
java/ql/lib/semmle/code/java/frameworks/google/Gson.qll
Normal file
36
java/ql/lib/semmle/code/java/frameworks/google/Gson.qll
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Provides classes for working with the Gson framework.
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.frameworks.android.Android
|
||||
import semmle.code.java.frameworks.android.Intent
|
||||
|
||||
/** The class `com.google.gson.Gson`. */
|
||||
class Gson extends RefType {
|
||||
Gson() { this.hasQualifiedName("com.google.gson", "Gson") }
|
||||
}
|
||||
|
||||
/** The `fromJson` deserialization method. */
|
||||
class GsonDeserializeMethod extends Method {
|
||||
GsonDeserializeMethod() {
|
||||
this.getDeclaringType() instanceof Gson and
|
||||
this.hasName("fromJson")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `intentNode` is an `Intent` used in the context `(T)intentNode.getParcelableExtra(...)` and
|
||||
* `parcelNode` is the corresponding parameter of `Parcelable.Creator<T> { public T createFromParcel(Parcel parcelNode) { }`,
|
||||
* where `T` is a concrete type implementing `Parcelable`.
|
||||
*/
|
||||
predicate intentFlowsToParcel(DataFlow::Node intentNode, DataFlow::Node parcelNode) {
|
||||
exists(MethodAccess getParcelableExtraCall, CreateFromParcelMethod cfpm, Type createdType |
|
||||
intentNode.asExpr() = getParcelableExtraCall.getQualifier() and
|
||||
getParcelableExtraCall.getMethod() instanceof IntentGetParcelableExtraMethod and
|
||||
DataFlow::localExprFlow(getParcelableExtraCall, any(Expr e | e.getType() = createdType)) and
|
||||
parcelNode.asParameter() = cfpm.getParameter(0) and
|
||||
cfpm.getReturnType() = createdType
|
||||
)
|
||||
}
|
||||
@@ -24,11 +24,5 @@ predicate jOOQSqlMethod(Method m) {
|
||||
}
|
||||
|
||||
private class SqlSinkCsv extends SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
//"package;type;overrides;name;signature;ext;spec;kind"
|
||||
"org.jooq;PlainSQL;false;;;Annotated;Argument[0];sql"
|
||||
]
|
||||
}
|
||||
override predicate row(string row) { row = "org.jooq;PlainSQL;false;;;Annotated;Argument[0];sql" }
|
||||
}
|
||||
|
||||
@@ -299,10 +299,7 @@ class RuntimeExitOrHaltMethod extends Method {
|
||||
(this.hasName("exit") or this.hasName("halt")) and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType().(PrimitiveType).hasName("int") and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.lang", "Runtime")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,10 +312,7 @@ class RuntimeAddOrRemoveShutdownHookMethod extends Method {
|
||||
(this.hasName("addShutdownHook") or this.hasName("removeShutdownHook")) and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "Thread") and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.lang", "Runtime")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,33 +408,29 @@ class ForbiddenSerializationMethod extends Method {
|
||||
|
||||
/**
|
||||
* A method named `enableReplaceObject` declared in
|
||||
* the class `java.io.ObjectInputStream` or a subclass thereof.
|
||||
* the class `java.io.ObjectOutputStream` or a subclass thereof.
|
||||
*/
|
||||
class EnableReplaceObjectMethod extends Method {
|
||||
EnableReplaceObjectMethod() {
|
||||
this.hasName("enableReplaceObject") and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType().(PrimitiveType).hasName("boolean") and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.io", "ObjectOutputStream")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof
|
||||
TypeObjectOutputStream
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method named `replaceObject` declared in
|
||||
* the class `java.io.ObjectInputStream` or a subclass thereof.
|
||||
* the class `java.io.ObjectOutputStream` or a subclass thereof.
|
||||
*/
|
||||
class ReplaceObjectMethod extends Method {
|
||||
ReplaceObjectMethod() {
|
||||
this.hasName("replaceObject") and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType() instanceof TypeObject and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.io", "ObjectOutputStream")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof
|
||||
TypeObjectOutputStream
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,10 +443,7 @@ class EnableResolveObjectMethod extends Method {
|
||||
this.hasName("enableResolveObject") and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType().(PrimitiveType).hasName("boolean") and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.io", "ObjectInputStream")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,10 +456,7 @@ class ResolveObjectMethod extends Method {
|
||||
this.hasName("resolveObject") and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType() instanceof TypeObject and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.io", "ObjectInputStream")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,10 +469,7 @@ class ResolveClassMethod extends Method {
|
||||
this.hasName("resolveClass") and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType().(RefType).hasQualifiedName("java.io", "ObjectStreamClass") and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.io", "ObjectInputStream")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,16 +481,8 @@ class ResolveProxyClassMethod extends Method {
|
||||
ResolveProxyClassMethod() {
|
||||
this.hasName("resolveProxyClass") and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0)
|
||||
.getType()
|
||||
.(Array)
|
||||
.getComponentType()
|
||||
.(RefType)
|
||||
.hasQualifiedName("java.lang", "String") and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.io", "ObjectInputStream")
|
||||
this.getParameter(0).getType().(Array).getComponentType() instanceof TypeString and
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeObjectInputStream
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,16 +571,13 @@ class SystemOrRuntimeLoadLibraryMethod extends Method {
|
||||
SystemOrRuntimeLoadLibraryMethod() {
|
||||
(this.hasName("load") or this.hasName("loadLibrary")) and
|
||||
this.getNumberOfParameters() = 1 and
|
||||
this.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "String") and
|
||||
this.getParameter(0).getType() instanceof TypeString and
|
||||
(
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.lang", "System") or
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.lang", "Runtime")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -619,9 +589,6 @@ class SystemOrRuntimeLoadLibraryMethod extends Method {
|
||||
class RuntimeExecMethod extends Method {
|
||||
RuntimeExecMethod() {
|
||||
this.hasName("exec") and
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.getSourceDeclaration()
|
||||
.hasQualifiedName("java.lang", "Runtime")
|
||||
this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof TypeRuntime
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ private DataFlow::Node getABodyBuilderWithExplicitContentType(Expr contentType)
|
||||
.hasQualifiedName("org.springframework.http", "ResponseEntity$BodyBuilder")
|
||||
)
|
||||
or
|
||||
DataFlow::localFlow(getABodyBuilderWithExplicitContentType(contentType), result)
|
||||
DataFlow::localFlowStep(getABodyBuilderWithExplicitContentType(contentType), result)
|
||||
}
|
||||
|
||||
private DataFlow::Node getASanitizedBodyBuilder() {
|
||||
|
||||
@@ -37,7 +37,7 @@ class SpringProfileExpr extends string {
|
||||
* A Spring profile expression that begins with "!", indicating a negated expression.
|
||||
*/
|
||||
class NotSpringProfileExpr extends SpringProfileExpr {
|
||||
NotSpringProfileExpr() { this.prefix(1) = "!" }
|
||||
NotSpringProfileExpr() { this.matches("!%") }
|
||||
|
||||
/**
|
||||
* Gets the profile described in this profile expression.
|
||||
|
||||
@@ -9,9 +9,7 @@ import semmle.code.java.security.XSS
|
||||
private class DefaultInformationLeakSinkModel extends SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"javax.servlet.http;HttpServletResponse;false;sendError;(int,String);;Argument[1];information-leak"
|
||||
]
|
||||
"javax.servlet.http;HttpServletResponse;false;sendError;(int,String);;Argument[1];information-leak"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,13 @@ private import semmle.code.java.frameworks.Jackson
|
||||
private import semmle.code.java.frameworks.Jabsorb
|
||||
private import semmle.code.java.frameworks.JoddJson
|
||||
private import semmle.code.java.frameworks.Flexjson
|
||||
private import semmle.code.java.frameworks.google.Gson
|
||||
private import semmle.code.java.frameworks.apache.Lang
|
||||
private import semmle.code.java.Reflection
|
||||
|
||||
private class ObjectInputStreamReadObjectMethod extends Method {
|
||||
ObjectInputStreamReadObjectMethod() {
|
||||
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
this.getDeclaringType().getASourceSupertype*() instanceof TypeObjectInputStream and
|
||||
(this.hasName("readObject") or this.hasName("readUnshared"))
|
||||
}
|
||||
}
|
||||
@@ -207,6 +208,10 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
||||
or
|
||||
m instanceof FlexjsonDeserializeMethod and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
m instanceof GsonDeserializeMethod and
|
||||
sink = ma.getArgument(0) and
|
||||
any(UnsafeTypeConfig config).hasFlowToExpr(ma.getArgument(1))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -249,6 +254,8 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
|
||||
createJacksonJsonParserStep(pred, succ)
|
||||
or
|
||||
createJacksonTreeNodeStep(pred, succ)
|
||||
or
|
||||
intentFlowsToParcel(pred, succ)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
@@ -362,9 +369,15 @@ class UnsafeTypeConfig extends TaintTracking2::Configuration {
|
||||
ma.getMethod() instanceof JabsorbUnmarshallMethod
|
||||
or
|
||||
ma.getMethod() instanceof JoddJsonParseMethod
|
||||
or
|
||||
ma.getMethod() instanceof GsonDeserializeMethod
|
||||
) and
|
||||
// Note `JacksonTypeDescriptorType` includes plain old `java.lang.Class`
|
||||
arg.getType() instanceof JacksonTypeDescriptorType and
|
||||
(
|
||||
arg.getType() instanceof JacksonTypeDescriptorType
|
||||
or
|
||||
arg.getType().(RefType).hasQualifiedName("java.lang.reflect", "Type")
|
||||
) and
|
||||
arg = sink.asExpr()
|
||||
)
|
||||
}
|
||||
@@ -375,7 +388,8 @@ class UnsafeTypeConfig extends TaintTracking2::Configuration {
|
||||
*/
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
resolveClassStep(fromNode, toNode) or
|
||||
looksLikeResolveClassStep(fromNode, toNode)
|
||||
looksLikeResolveClassStep(fromNode, toNode) or
|
||||
intentFlowsToParcel(fromNode, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ class Pom extends ProtoPom {
|
||||
* occurs by considering the properties defined by this project or an ancestor project.
|
||||
*/
|
||||
string resolvePlaceholder(string name) {
|
||||
if name.prefix(8) = "project."
|
||||
if name.matches("project.%")
|
||||
then
|
||||
exists(PomElement p |
|
||||
p = getProjectProperty() and
|
||||
|
||||
@@ -108,7 +108,7 @@ class XMLParent extends @xmlparent {
|
||||
}
|
||||
|
||||
/** Gets the text value contained in this XML parent. */
|
||||
string getTextValue() { result = allCharactersString() }
|
||||
string getTextValue() { result = this.allCharactersString() }
|
||||
|
||||
/** Gets a printable representation of this XML parent. */
|
||||
string toString() { result = this.getName() }
|
||||
@@ -119,7 +119,7 @@ class XMLFile extends XMLParent, File {
|
||||
XMLFile() { xmlEncoding(this, _) }
|
||||
|
||||
/** Gets a printable representation of this XML file. */
|
||||
override string toString() { result = getName() }
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
/** Gets the name of this XML file. */
|
||||
override string getName() { result = File.super.getAbsolutePath() }
|
||||
@@ -129,14 +129,14 @@ class XMLFile extends XMLParent, File {
|
||||
*
|
||||
* Gets the path of this XML file.
|
||||
*/
|
||||
deprecated string getPath() { result = getAbsolutePath() }
|
||||
deprecated string getPath() { result = this.getAbsolutePath() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of the folder that contains this XML file.
|
||||
*/
|
||||
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
|
||||
deprecated string getFolder() { result = this.getParentContainer().getAbsolutePath() }
|
||||
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this, result) }
|
||||
@@ -200,7 +200,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
||||
*/
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = getName() }
|
||||
predicate hasName(string name) { name = this.getName() }
|
||||
|
||||
/** Gets the name of this XML element. */
|
||||
override string getName() { xmlElements(this, result, _, _, _) }
|
||||
@@ -239,7 +239,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
|
||||
|
||||
/** Gets a printable representation of this XML element. */
|
||||
override string toString() { result = getName() }
|
||||
override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user