mirror of
https://github.com/github/codeql.git
synced 2025-12-22 11:46:32 +01:00
Merge pull request #12563 from egregius313/egregius313/refactor-java-libs-to-dataflow-modules
Java: Refactor Java query libraries to use dataflow modules
This commit is contained in:
@@ -42,8 +42,12 @@ class JsonIoUseMapsSetter extends MethodAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A data flow configuration tracing flow from JsonIo safe settings. */
|
/**
|
||||||
class SafeJsonIoConfig extends DataFlow2::Configuration {
|
* DEPRECATED: Use `SafeJsonIoFlow` instead.
|
||||||
|
*
|
||||||
|
* A data flow configuration tracing flow from JsonIo safe settings.
|
||||||
|
*/
|
||||||
|
deprecated class SafeJsonIoConfig extends DataFlow2::Configuration {
|
||||||
SafeJsonIoConfig() { this = "UnsafeDeserialization::SafeJsonIoConfig" }
|
SafeJsonIoConfig() { this = "UnsafeDeserialization::SafeJsonIoConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
override predicate isSource(DataFlow::Node src) {
|
||||||
@@ -65,3 +69,30 @@ class SafeJsonIoConfig extends DataFlow2::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data flow configuration tracing flow from JsonIo safe settings.
|
||||||
|
*/
|
||||||
|
module SafeJsonIoConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) {
|
||||||
|
exists(MethodAccess ma |
|
||||||
|
ma instanceof JsonIoUseMapsSetter and
|
||||||
|
src.asExpr() = ma.getQualifier()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(MethodAccess ma |
|
||||||
|
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||||
|
sink.asExpr() = ma.getArgument(1)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(ClassInstanceExpr cie |
|
||||||
|
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
|
||||||
|
sink.asExpr() = cie.getArgument(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tracks flow from JsonIo safe settings. */
|
||||||
|
module SafeJsonIoFlow = DataFlow::Global<SafeJsonIoConfig>;
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.dataflow.DataFlow2
|
|
||||||
import semmle.code.java.dataflow.DataFlow3
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class `org.yaml.snakeyaml.constructor.SafeConstructor`.
|
* The class `org.yaml.snakeyaml.constructor.SafeConstructor`.
|
||||||
@@ -30,28 +28,28 @@ class Yaml extends RefType {
|
|||||||
Yaml() { this.getAnAncestor().hasQualifiedName("org.yaml.snakeyaml", "Yaml") }
|
Yaml() { this.getAnAncestor().hasQualifiedName("org.yaml.snakeyaml", "Yaml") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeYamlConstructionFlowConfig extends DataFlow3::Configuration {
|
private DataFlow::ExprNode yamlClassInstanceExprArgument(ClassInstanceExpr cie) {
|
||||||
SafeYamlConstructionFlowConfig() { this = "SnakeYaml::SafeYamlConstructionFlowConfig" }
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
|
||||||
src.asExpr() instanceof SafeSnakeYamlConstruction
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink = this.yamlClassInstanceExprArgument(_) }
|
|
||||||
|
|
||||||
private DataFlow::ExprNode yamlClassInstanceExprArgument(ClassInstanceExpr cie) {
|
|
||||||
cie.getConstructedType() instanceof Yaml and
|
cie.getConstructedType() instanceof Yaml and
|
||||||
result.getExpr() = cie.getArgument(0)
|
result.getExpr() = cie.getArgument(0)
|
||||||
}
|
|
||||||
|
|
||||||
ClassInstanceExpr getSafeYaml() { this.hasFlowTo(this.yamlClassInstanceExprArgument(result)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeYamlConstructionFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSnakeYamlConstruction }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink = yamlClassInstanceExprArgument(_) }
|
||||||
|
|
||||||
|
additional ClassInstanceExpr getSafeYaml() {
|
||||||
|
SafeYamlConstructionFlow::flowTo(yamlClassInstanceExprArgument(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module SafeYamlConstructionFlow = DataFlow::Global<SafeYamlConstructionFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of `Yaml` that does not allow arbitrary constructor to be called.
|
* An instance of `Yaml` that does not allow arbitrary constructor to be called.
|
||||||
*/
|
*/
|
||||||
private class SafeYaml extends ClassInstanceExpr {
|
private class SafeYaml extends ClassInstanceExpr {
|
||||||
SafeYaml() { exists(SafeYamlConstructionFlowConfig conf | conf.getSafeYaml() = this) }
|
SafeYaml() { SafeYamlConstructionFlowConfig::getSafeYaml() = this }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A call to a parse method of `Yaml`. */
|
/** A call to a parse method of `Yaml`. */
|
||||||
@@ -65,23 +63,25 @@ private class SnakeYamlParse extends MethodAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeYamlFlowConfig extends DataFlow2::Configuration {
|
private module SafeYamlFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeYamlFlowConfig() { this = "SnakeYaml::SafeYamlFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeYaml }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeYaml }
|
predicate isSink(DataFlow::Node sink) { sink = yamlParseQualifier(_) }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink = this.yamlParseQualifier(_) }
|
additional DataFlow::ExprNode yamlParseQualifier(SnakeYamlParse syp) {
|
||||||
|
|
||||||
private DataFlow::ExprNode yamlParseQualifier(SnakeYamlParse syp) {
|
|
||||||
result.getExpr() = syp.getQualifier()
|
result.getExpr() = syp.getQualifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
SnakeYamlParse getASafeSnakeYamlParse() { this.hasFlowTo(this.yamlParseQualifier(result)) }
|
additional SnakeYamlParse getASafeSnakeYamlParse() {
|
||||||
|
SafeYamlFlow::flowTo(yamlParseQualifier(result))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeYamlFlow = DataFlow::Global<SafeYamlFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A call to a parse method of `Yaml` that allows arbitrary constructor to be called.
|
* A call to a parse method of `Yaml` that allows arbitrary constructor to be called.
|
||||||
*/
|
*/
|
||||||
class UnsafeSnakeYamlParse extends SnakeYamlParse {
|
class UnsafeSnakeYamlParse extends SnakeYamlParse {
|
||||||
UnsafeSnakeYamlParse() { not exists(SafeYamlFlowConfig sy | sy.getASafeSnakeYamlParse() = this) }
|
UnsafeSnakeYamlParse() { not SafeYamlFlowConfig::getASafeSnakeYamlParse() = this }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,24 +136,22 @@ private class GuavaRegexFlowStep extends RegexAdditionalFlowStep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RegexFlowConf extends DataFlow2::Configuration {
|
private module RegexFlowConfig implements DataFlow::ConfigSig {
|
||||||
RegexFlowConf() { this = "RegexFlowConfig" }
|
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ExploitableStringLiteral }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node node) {
|
predicate isSink(DataFlow::Node node) { node instanceof RegexFlowSink }
|
||||||
node.asExpr() instanceof ExploitableStringLiteral
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node) { node instanceof RegexFlowSink }
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
||||||
any(RegexAdditionalFlowStep s).step(node1, node2)
|
any(RegexAdditionalFlowStep s).step(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isBarrier(DataFlow::Node node) {
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass
|
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module RegexFlow = DataFlow::Global<RegexFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `regex` is used as a regex, with the mode `mode` (if known).
|
* Holds if `regex` is used as a regex, with the mode `mode` (if known).
|
||||||
* If regex mode is not known, `mode` will be `"None"`.
|
* If regex mode is not known, `mode` will be `"None"`.
|
||||||
@@ -162,7 +160,7 @@ private class RegexFlowConf extends DataFlow2::Configuration {
|
|||||||
* and therefore may be relevant for ReDoS queries are considered.
|
* and therefore may be relevant for ReDoS queries are considered.
|
||||||
*/
|
*/
|
||||||
predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_string) {
|
predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_string) {
|
||||||
any(RegexFlowConf c).hasFlow(DataFlow2::exprNode(regex), _) and
|
RegexFlow::flow(DataFlow::exprNode(regex), _) and
|
||||||
mode = "None" and // TODO: proper mode detection
|
mode = "None" and // TODO: proper mode detection
|
||||||
(if matchesFullString(regex) then match_full_string = true else match_full_string = false)
|
(if matchesFullString(regex) then match_full_string = true else match_full_string = false)
|
||||||
}
|
}
|
||||||
@@ -172,9 +170,9 @@ predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_strin
|
|||||||
* as though it was implicitly surrounded by ^ and $.
|
* as though it was implicitly surrounded by ^ and $.
|
||||||
*/
|
*/
|
||||||
private predicate matchesFullString(StringLiteral regex) {
|
private predicate matchesFullString(StringLiteral regex) {
|
||||||
exists(RegexFlowConf c, RegexFlowSink sink |
|
exists(RegexFlowSink sink |
|
||||||
sink.matchesFullString() and
|
sink.matchesFullString() and
|
||||||
c.hasFlow(DataFlow2::exprNode(regex), sink)
|
RegexFlow::flow(DataFlow::exprNode(regex), sink)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,8 +183,8 @@ private predicate matchesFullString(StringLiteral regex) {
|
|||||||
* and therefore may be relevant for ReDoS queries are considered.
|
* and therefore may be relevant for ReDoS queries are considered.
|
||||||
*/
|
*/
|
||||||
predicate regexMatchedAgainst(StringLiteral regex, Expr str) {
|
predicate regexMatchedAgainst(StringLiteral regex, Expr str) {
|
||||||
exists(RegexFlowConf c, RegexFlowSink sink |
|
exists(RegexFlowSink sink |
|
||||||
str = sink.getStringArgument() and
|
str = sink.getStringArgument() and
|
||||||
c.hasFlow(DataFlow2::exprNode(regex), sink)
|
RegexFlow::flow(DataFlow::exprNode(regex), sink)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,10 @@ deprecated class SensitiveCommunicationConfig extends TaintTracking::Configurati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module SensitiveCommunicationConfig implements DataFlow::ConfigSig {
|
/**
|
||||||
|
* Taint configuration tracking flow from variables containing sensitive information to broadcast Intents.
|
||||||
|
*/
|
||||||
|
module SensitiveCommunicationConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveInfoExpr }
|
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveInfoExpr }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ private import semmle.code.java.security.ArbitraryApkInstallation
|
|||||||
* A dataflow configuration for flow from an external source of an APK to the
|
* A dataflow configuration for flow from an external source of an APK to the
|
||||||
* `setData[AndType][AndNormalize]` method of an intent.
|
* `setData[AndType][AndNormalize]` method of an intent.
|
||||||
*/
|
*/
|
||||||
private module ApkInstallationConfig implements DataFlow::ConfigSig {
|
module ApkInstallationConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node node) { node instanceof ExternalApkSource }
|
predicate isSource(DataFlow::Node node) { node instanceof ExternalApkSource }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node node) {
|
predicate isSink(DataFlow::Node node) {
|
||||||
|
|||||||
@@ -29,16 +29,16 @@ class LocalDatabaseOpenMethodAccess extends Storable, Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAnInput() {
|
override Expr getAnInput() {
|
||||||
exists(LocalDatabaseFlowConfig config, DataFlow::Node database |
|
exists(DataFlow::Node database |
|
||||||
localDatabaseInput(database, result) and
|
localDatabaseInput(database, result) and
|
||||||
config.hasFlow(DataFlow::exprNode(this), database)
|
LocalDatabaseFlow::flow(DataFlow::exprNode(this), database)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAStore() {
|
override Expr getAStore() {
|
||||||
exists(LocalDatabaseFlowConfig config, DataFlow::Node database |
|
exists(DataFlow::Node database |
|
||||||
localDatabaseStore(database, result) and
|
localDatabaseStore(database, result) and
|
||||||
config.hasFlow(DataFlow::exprNode(this), database)
|
LocalDatabaseFlow::flow(DataFlow::exprNode(this), database)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,19 +93,17 @@ private predicate localDatabaseStore(DataFlow::Node database, MethodAccess store
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LocalDatabaseFlowConfig extends DataFlow::Configuration {
|
private module LocalDatabaseFlowConfig implements DataFlow::ConfigSig {
|
||||||
LocalDatabaseFlowConfig() { this = "LocalDatabaseFlowConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
source.asExpr() instanceof LocalDatabaseOpenMethodAccess
|
source.asExpr() instanceof LocalDatabaseOpenMethodAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
localDatabaseInput(sink, _) or
|
localDatabaseInput(sink, _) or
|
||||||
localDatabaseStore(sink, _)
|
localDatabaseStore(sink, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||||
// Adds a step for tracking databases through field flow, that is, a database is opened and
|
// Adds a step for tracking databases through field flow, that is, a database is opened and
|
||||||
// assigned to a field, and then an input or store method is called on that field elsewhere.
|
// assigned to a field, and then an input or store method is called on that field elsewhere.
|
||||||
exists(Field f |
|
exists(Field f |
|
||||||
@@ -115,3 +113,5 @@ private class LocalDatabaseFlowConfig extends DataFlow::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module LocalDatabaseFlow = DataFlow::Global<LocalDatabaseFlowConfig>;
|
||||||
|
|||||||
@@ -24,16 +24,16 @@ class LocalFileOpenCall extends Storable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAnInput() {
|
override Expr getAnInput() {
|
||||||
exists(FilesystemFlowConfig conf, DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
filesystemInput(n, result) and
|
filesystemInput(n, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), n)
|
FilesystemFlow::flow(DataFlow::exprNode(this), n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAStore() {
|
override Expr getAStore() {
|
||||||
exists(FilesystemFlowConfig conf, DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
closesFile(n, result) and
|
closesFile(n, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), n)
|
FilesystemFlow::flow(DataFlow::exprNode(this), n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,17 +79,15 @@ private class CloseFileMethod extends Method {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FilesystemFlowConfig extends DataFlow::Configuration {
|
private module FilesystemFlowConfig implements DataFlow::ConfigSig {
|
||||||
FilesystemFlowConfig() { this = "FilesystemFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LocalFileOpenCall }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LocalFileOpenCall }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
filesystemInput(sink, _) or
|
filesystemInput(sink, _) or
|
||||||
closesFile(sink, _)
|
closesFile(sink, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
// Add nested Writer constructors as extra data flow steps
|
// Add nested Writer constructors as extra data flow steps
|
||||||
exists(ClassInstanceExpr cie |
|
exists(ClassInstanceExpr cie |
|
||||||
cie.getConstructedType().getAnAncestor().hasQualifiedName("java.io", "Writer") and
|
cie.getConstructedType().getAnAncestor().hasQualifiedName("java.io", "Writer") and
|
||||||
@@ -98,3 +96,5 @@ private class FilesystemFlowConfig extends DataFlow::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module FilesystemFlow = DataFlow::Global<FilesystemFlowConfig>;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ private class ClassCleartextStorageSink extends CleartextStorageSink {
|
|||||||
abstract class ClassStore extends Storable, ClassInstanceExpr {
|
abstract class ClassStore extends Storable, ClassInstanceExpr {
|
||||||
/** Gets an input, for example `input` in `instance.password = input`. */
|
/** Gets an input, for example `input` in `instance.password = input`. */
|
||||||
override Expr getAnInput() {
|
override Expr getAnInput() {
|
||||||
exists(ClassStoreFlowConfig conf, DataFlow::Node instance |
|
exists(DataFlow::Node instance |
|
||||||
conf.hasFlow(DataFlow::exprNode(this), instance) and
|
ClassStoreFlow::flow(DataFlow::exprNode(this), instance) and
|
||||||
result = getInstanceInput(instance, this.getConstructor().getDeclaringType())
|
result = getInstanceInput(instance, this.getConstructor().getDeclaringType())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -40,9 +40,9 @@ private class Serializable extends ClassStore {
|
|||||||
|
|
||||||
/** Gets a store, for example `outputStream.writeObject(instance)`. */
|
/** Gets a store, for example `outputStream.writeObject(instance)`. */
|
||||||
override Expr getAStore() {
|
override Expr getAStore() {
|
||||||
exists(ClassStoreFlowConfig conf, DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
serializableStore(n, result) and
|
serializableStore(n, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), n)
|
ClassStoreFlow::flow(DataFlow::exprNode(this), n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,9 +53,9 @@ private class Marshallable extends ClassStore {
|
|||||||
|
|
||||||
/** Gets a store, for example `marshaller.marshal(instance)`. */
|
/** Gets a store, for example `marshaller.marshal(instance)`. */
|
||||||
override Expr getAStore() {
|
override Expr getAStore() {
|
||||||
exists(ClassStoreFlowConfig conf, DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
marshallableStore(n, result) and
|
marshallableStore(n, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), n)
|
ClassStoreFlow::flow(DataFlow::exprNode(this), n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,20 +73,20 @@ private Expr getInstanceInput(DataFlow::Node instance, RefType t) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ClassStoreFlowConfig extends DataFlow::Configuration {
|
private module ClassStoreFlowConfig implements DataFlow::ConfigSig {
|
||||||
ClassStoreFlowConfig() { this = "ClassStoreFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassStore }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassStore }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(getInstanceInput(sink, _)) or
|
exists(getInstanceInput(sink, _)) or
|
||||||
serializableStore(sink, _) or
|
serializableStore(sink, _) or
|
||||||
marshallableStore(sink, _)
|
marshallableStore(sink, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 1 }
|
int fieldFlowBranchLimit() { result = 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module ClassStoreFlow = DataFlow::Global<ClassStoreFlowConfig>;
|
||||||
|
|
||||||
private predicate serializableStore(DataFlow::Node instance, Expr store) {
|
private predicate serializableStore(DataFlow::Node instance, Expr store) {
|
||||||
exists(MethodAccess m |
|
exists(MethodAccess m |
|
||||||
store = m and
|
store = m and
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ class Cookie extends Storable, ClassInstanceExpr {
|
|||||||
|
|
||||||
/** Gets a store, for example `response.addCookie(cookie);`. */
|
/** Gets a store, for example `response.addCookie(cookie);`. */
|
||||||
override Expr getAStore() {
|
override Expr getAStore() {
|
||||||
exists(CookieToStoreFlowConfig conf, DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
cookieStore(n, result) and
|
cookieStore(n, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), n)
|
CookieToStoreFlow::flow(DataFlow::exprNode(this), n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,12 +37,12 @@ private predicate cookieStore(DataFlow::Node cookie, Expr store) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CookieToStoreFlowConfig extends DataFlow3::Configuration {
|
private module CookieToStoreFlowConfig implements DataFlow::ConfigSig {
|
||||||
CookieToStoreFlowConfig() { this = "CookieToStoreFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof Cookie }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof Cookie }
|
predicate isSink(DataFlow::Node sink) { cookieStore(sink, _) }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { cookieStore(sink, _) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module CookieToStoreFlow = DataFlow::Global<CookieToStoreFlowConfig>;
|
||||||
|
|
||||||
private Expr cookieInput(Cookie c) { result = c.getArgument(1) }
|
private Expr cookieInput(Cookie c) { result = c.getArgument(1) }
|
||||||
|
|||||||
@@ -19,17 +19,17 @@ class Properties extends Storable, ClassInstanceExpr {
|
|||||||
|
|
||||||
/** Gets an input, for example `input` in `props.setProperty("password", input);`. */
|
/** Gets an input, for example `input` in `props.setProperty("password", input);`. */
|
||||||
override Expr getAnInput() {
|
override Expr getAnInput() {
|
||||||
exists(PropertiesFlowConfig conf, DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
propertiesInput(n, result) and
|
propertiesInput(n, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), n)
|
PropertiesFlow::flow(DataFlow::exprNode(this), n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a store, for example `props.store(outputStream, "...")`. */
|
/** Gets a store, for example `props.store(outputStream, "...")`. */
|
||||||
override Expr getAStore() {
|
override Expr getAStore() {
|
||||||
exists(PropertiesFlowConfig conf, DataFlow::Node n |
|
exists(DataFlow::Node n |
|
||||||
propertiesStore(n, result) and
|
propertiesStore(n, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), n)
|
PropertiesFlow::flow(DataFlow::exprNode(this), n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,13 +50,13 @@ private predicate propertiesStore(DataFlow::Node prop, Expr store) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PropertiesFlowConfig extends DataFlow::Configuration {
|
private module PropertiesFlowConfig implements DataFlow::ConfigSig {
|
||||||
PropertiesFlowConfig() { this = "PropertiesFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof Properties }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof Properties }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
propertiesInput(sink, _) or
|
propertiesInput(sink, _) or
|
||||||
propertiesStore(sink, _)
|
propertiesStore(sink, _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module PropertiesFlow = DataFlow::Global<PropertiesFlowConfig>;
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ class CleartextStorageAdditionalTaintStep extends Unit {
|
|||||||
class SensitiveSource extends Expr instanceof SensitiveExpr {
|
class SensitiveSource extends Expr instanceof SensitiveExpr {
|
||||||
/** Holds if this source flows to the `sink`. */
|
/** Holds if this source flows to the `sink`. */
|
||||||
predicate flowsTo(Expr sink) {
|
predicate flowsTo(Expr sink) {
|
||||||
exists(SensitiveSourceFlowConfig conf |
|
SensitiveSourceFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
|
||||||
conf.hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,27 +38,25 @@ abstract class Storable extends Call {
|
|||||||
abstract Expr getAStore();
|
abstract Expr getAStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SensitiveSourceFlowConfig extends TaintTracking2::Configuration {
|
private module SensitiveSourceFlowConfig implements DataFlow::ConfigSig {
|
||||||
SensitiveSourceFlowConfig() { this = "SensitiveSourceFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }
|
predicate isSink(DataFlow::Node sink) { sink instanceof CleartextStorageSink }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof CleartextStorageSink }
|
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof CleartextStorageSanitizer }
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||||
sanitizer instanceof CleartextStorageSanitizer
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
|
||||||
any(CleartextStorageAdditionalTaintStep c).step(n1, n2)
|
any(CleartextStorageAdditionalTaintStep c).step(n1, n2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SensitiveSourceFlow = TaintTracking::Global<SensitiveSourceFlowConfig>;
|
||||||
|
|
||||||
private class DefaultCleartextStorageSanitizer extends CleartextStorageSanitizer {
|
private class DefaultCleartextStorageSanitizer extends CleartextStorageSanitizer {
|
||||||
DefaultCleartextStorageSanitizer() {
|
DefaultCleartextStorageSanitizer() {
|
||||||
this.getType() instanceof NumericType or
|
this.getType() instanceof NumericType or
|
||||||
this.getType() instanceof BooleanType or
|
this.getType() instanceof BooleanType or
|
||||||
exists(EncryptedValueFlowConfig conf | conf.hasFlow(_, this))
|
EncryptedValueFlow::flowTo(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,12 +72,10 @@ private class EncryptedSensitiveMethodAccess extends MethodAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Flow configuration for encryption methods flowing to inputs of persistent storage. */
|
/** Flow configuration for encryption methods flowing to inputs of persistent storage. */
|
||||||
private class EncryptedValueFlowConfig extends DataFlow4::Configuration {
|
private module EncryptedValueFlowConfig implements DataFlow::ConfigSig {
|
||||||
EncryptedValueFlowConfig() { this = "EncryptedValueFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof EncryptedSensitiveMethodAccess }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SensitiveExpr }
|
||||||
src.asExpr() instanceof EncryptedSensitiveMethodAccess
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SensitiveExpr }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module EncryptedValueFlow = DataFlow::Global<EncryptedValueFlowConfig>;
|
||||||
|
|||||||
@@ -28,17 +28,17 @@ class SharedPreferencesEditorMethodAccess extends Storable, MethodAccess {
|
|||||||
|
|
||||||
/** Gets an input, for example `password` in `editor.putString("password", password);`. */
|
/** Gets an input, for example `password` in `editor.putString("password", password);`. */
|
||||||
override Expr getAnInput() {
|
override Expr getAnInput() {
|
||||||
exists(SharedPreferencesFlowConfig conf, DataFlow::Node editor |
|
exists(DataFlow::Node editor |
|
||||||
sharedPreferencesInput(editor, result) and
|
sharedPreferencesInput(editor, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), editor)
|
SharedPreferencesFlow::flow(DataFlow::exprNode(this), editor)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a store, for example `editor.commit();`. */
|
/** Gets a store, for example `editor.commit();`. */
|
||||||
override Expr getAStore() {
|
override Expr getAStore() {
|
||||||
exists(SharedPreferencesFlowConfig conf, DataFlow::Node editor |
|
exists(DataFlow::Node editor |
|
||||||
sharedPreferencesStore(editor, result) and
|
sharedPreferencesStore(editor, result) and
|
||||||
conf.hasFlow(DataFlow::exprNode(this), editor)
|
SharedPreferencesFlow::flow(DataFlow::exprNode(this), editor)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,15 +65,15 @@ private predicate sharedPreferencesStore(DataFlow::Node editor, MethodAccess m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Flow from `SharedPreferences.Editor` to either a setter or a store method. */
|
/** Flow from `SharedPreferences.Editor` to either a setter or a store method. */
|
||||||
private class SharedPreferencesFlowConfig extends DataFlow::Configuration {
|
private module SharedPreferencesFlowConfig implements DataFlow::ConfigSig {
|
||||||
SharedPreferencesFlowConfig() { this = "SharedPreferencesFlowConfig" }
|
predicate isSource(DataFlow::Node src) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
|
||||||
src.asExpr() instanceof SharedPreferencesEditorMethodAccess
|
src.asExpr() instanceof SharedPreferencesEditorMethodAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
sharedPreferencesInput(sink, _) or
|
sharedPreferencesInput(sink, _) or
|
||||||
sharedPreferencesStore(sink, _)
|
sharedPreferencesStore(sink, _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SharedPreferencesFlow = DataFlow::Global<SharedPreferencesFlowConfig>;
|
||||||
|
|||||||
@@ -37,9 +37,11 @@ private predicate endsWithStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `ConditionalBypassFlow` instead.
|
||||||
|
*
|
||||||
* A taint tracking configuration for untrusted data flowing to sensitive conditions.
|
* A taint tracking configuration for untrusted data flowing to sensitive conditions.
|
||||||
*/
|
*/
|
||||||
class ConditionalBypassFlowConfig extends TaintTracking::Configuration {
|
deprecated class ConditionalBypassFlowConfig extends TaintTracking::Configuration {
|
||||||
ConditionalBypassFlowConfig() { this = "ConditionalBypassFlowConfig" }
|
ConditionalBypassFlowConfig() { this = "ConditionalBypassFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
@@ -50,3 +52,21 @@ class ConditionalBypassFlowConfig extends TaintTracking::Configuration {
|
|||||||
endsWithStep(node1, node2)
|
endsWithStep(node1, node2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint tracking configuration for untrusted data flowing to sensitive conditions.
|
||||||
|
*/
|
||||||
|
module ConditionalBypassFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { conditionControlsMethod(_, sink.asExpr()) }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
endsWithStep(node1, node2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taint tracking flow for untrusted data flowing to sensitive conditions.
|
||||||
|
*/
|
||||||
|
module ConditionalBypassFlow = TaintTracking::Global<ConditionalBypassFlowConfig>;
|
||||||
|
|||||||
@@ -98,8 +98,12 @@ class ExternalApiDataNode extends DataFlow::Node {
|
|||||||
/** DEPRECATED: Alias for ExternalApiDataNode */
|
/** DEPRECATED: Alias for ExternalApiDataNode */
|
||||||
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
||||||
|
|
||||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
/**
|
||||||
class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
* DEPRECATED: Use `UntrustedDataToExternalApiFlow` instead.
|
||||||
|
*
|
||||||
|
* A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s.
|
||||||
|
*/
|
||||||
|
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||||
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
|
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
@@ -107,17 +111,29 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
|||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taint tracking configuration for flow from `RemoteFlowSource`s to `ExternalApiDataNode`s.
|
||||||
|
*/
|
||||||
|
module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks flow from untrusted data to external APIs.
|
||||||
|
*/
|
||||||
|
module UntrustedDataToExternalApiFlow = TaintTracking::Global<UntrustedDataToExternalApiConfig>;
|
||||||
|
|
||||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||||
|
|
||||||
/** A node representing untrusted data being passed to an external API. */
|
/** A node representing untrusted data being passed to an external API. */
|
||||||
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||||
UntrustedExternalApiDataNode() { any(UntrustedDataToExternalApiConfig c).hasFlow(_, this) }
|
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flowTo(this) }
|
||||||
|
|
||||||
/** Gets a source of untrusted data which is passed to this external API data node. */
|
/** Gets a source of untrusted data which is passed to this external API data node. */
|
||||||
DataFlow::Node getAnUntrustedSource() {
|
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||||
any(UntrustedDataToExternalApiConfig c).hasFlow(result, this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ deprecated class FragmentInjectionTaintConf extends TaintTracking::Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FragmentInjectionTaintConfig implements DataFlow::ConfigSig {
|
/**
|
||||||
|
* A taint-tracking configuration for unsafe user input
|
||||||
|
* that is used to create Android fragments dynamically.
|
||||||
|
*/
|
||||||
|
module FragmentInjectionTaintConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) { sink instanceof FragmentInjectionSink }
|
predicate isSink(DataFlow::Node sink) { sink instanceof FragmentInjectionSink }
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import semmle.code.java.dataflow.DataFlow
|
|||||||
import HardcodedCredentials
|
import HardcodedCredentials
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `HardcodedCredentialApiCallFlow` instead.
|
||||||
|
*
|
||||||
* A data-flow configuration that tracks flow from a hard-coded credential in a call to a sensitive Java API which may compromise security.
|
* A data-flow configuration that tracks flow from a hard-coded credential in a call to a sensitive Java API which may compromise security.
|
||||||
*/
|
*/
|
||||||
class HardcodedCredentialApiCallConfiguration extends DataFlow::Configuration {
|
deprecated class HardcodedCredentialApiCallConfiguration extends DataFlow::Configuration {
|
||||||
HardcodedCredentialApiCallConfiguration() { this = "HardcodedCredentialApiCallConfiguration" }
|
HardcodedCredentialApiCallConfiguration() { this = "HardcodedCredentialApiCallConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node n) {
|
override predicate isSource(DataFlow::Node n) {
|
||||||
@@ -52,3 +54,53 @@ class HardcodedCredentialApiCallConfiguration extends DataFlow::Configuration {
|
|||||||
n.asExpr().(MethodAccess).getMethod() instanceof MethodSystemGetenv
|
n.asExpr().(MethodAccess).getMethod() instanceof MethodSystemGetenv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data-flow configuration that tracks flow from a hard-coded credential in a call to a sensitive Java API which may compromise security.
|
||||||
|
*/
|
||||||
|
module HardcodedCredentialApiCallConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node n) {
|
||||||
|
n.asExpr() instanceof HardcodedExpr and
|
||||||
|
not n.asExpr().getEnclosingCallable() instanceof ToStringMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node n) { n.asExpr() instanceof CredentialsApiSink }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
node1.asExpr().getType() instanceof TypeString and
|
||||||
|
(
|
||||||
|
exists(MethodAccess ma | ma.getMethod().hasName(["getBytes", "toCharArray"]) |
|
||||||
|
node2.asExpr() = ma and
|
||||||
|
ma.getQualifier() = node1.asExpr()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// These base64 routines are usually taint propagators, and this is not a general
|
||||||
|
// TaintTracking::Configuration, so we must specifically include them here
|
||||||
|
// as a common transform applied to a constant before passing to a remote API.
|
||||||
|
exists(MethodAccess ma |
|
||||||
|
ma.getMethod()
|
||||||
|
.hasQualifiedName([
|
||||||
|
"java.util", "cn.hutool.core.codec", "org.apache.shiro.codec",
|
||||||
|
"apache.commons.codec.binary", "org.springframework.util"
|
||||||
|
], ["Base64$Encoder", "Base64$Decoder", "Base64", "Base64Utils"],
|
||||||
|
[
|
||||||
|
"encode", "encodeToString", "decode", "decodeBase64", "encodeBase64",
|
||||||
|
"encodeBase64Chunked", "encodeBase64String", "encodeBase64URLSafe",
|
||||||
|
"encodeBase64URLSafeString"
|
||||||
|
])
|
||||||
|
|
|
||||||
|
node1.asExpr() = ma.getArgument(0) and
|
||||||
|
node2.asExpr() = ma
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node n) {
|
||||||
|
n.asExpr().(MethodAccess).getMethod() instanceof MethodSystemGetenv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks flow from a hard-coded credential in a call to a sensitive Java API which may compromise security.
|
||||||
|
*/
|
||||||
|
module HardcodedCredentialApiCallFlow = DataFlow::Global<HardcodedCredentialApiCallConfig>;
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import semmle.code.java.frameworks.Networking
|
|||||||
import semmle.code.java.security.HttpsUrls
|
import semmle.code.java.security.HttpsUrls
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `HttpsStringToUrlOpenMethodFlow` instead.
|
||||||
|
*
|
||||||
* A taint tracking configuration for HTTP connections.
|
* A taint tracking configuration for HTTP connections.
|
||||||
*/
|
*/
|
||||||
class HttpStringToUrlOpenMethodFlowConfig extends TaintTracking::Configuration {
|
deprecated class HttpStringToUrlOpenMethodFlowConfig extends TaintTracking::Configuration {
|
||||||
HttpStringToUrlOpenMethodFlowConfig() { this = "HttpStringToUrlOpenMethodFlowConfig" }
|
HttpStringToUrlOpenMethodFlowConfig() { this = "HttpStringToUrlOpenMethodFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HttpStringLiteral }
|
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HttpStringLiteral }
|
||||||
@@ -23,3 +25,25 @@ class HttpStringToUrlOpenMethodFlowConfig extends TaintTracking::Configuration {
|
|||||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint tracking configuration for HTTP connections.
|
||||||
|
*/
|
||||||
|
module HttpStringToUrlOpenMethodFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HttpStringLiteral }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof UrlOpenSink }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
any(HttpUrlsAdditionalTaintStep c).step(node1, node2)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect taint flow of HTTP connections.
|
||||||
|
*/
|
||||||
|
module HttpStringToUrlOpenMethodFlow = TaintTracking::Global<HttpStringToUrlOpenMethodFlowConfig>;
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import semmle.code.java.frameworks.android.PendingIntent
|
|||||||
import semmle.code.java.security.ImplicitPendingIntents
|
import semmle.code.java.security.ImplicitPendingIntents
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `ImplicitPendingIntentStartFlow` instead.
|
||||||
|
*
|
||||||
* A taint tracking configuration for implicit `PendingIntent`s
|
* A taint tracking configuration for implicit `PendingIntent`s
|
||||||
* being wrapped in another implicit `Intent` that gets started.
|
* being wrapped in another implicit `Intent` that gets started.
|
||||||
*/
|
*/
|
||||||
class ImplicitPendingIntentStartConf extends TaintTracking::Configuration {
|
deprecated class ImplicitPendingIntentStartConf extends TaintTracking::Configuration {
|
||||||
ImplicitPendingIntentStartConf() { this = "ImplicitPendingIntentStartConf" }
|
ImplicitPendingIntentStartConf() { this = "ImplicitPendingIntentStartConf" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||||
@@ -52,3 +54,50 @@ class ImplicitPendingIntentStartConf extends TaintTracking::Configuration {
|
|||||||
c instanceof DataFlow::ArrayContent
|
c instanceof DataFlow::ArrayContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint tracking configuration for implicit `PendingIntent`s
|
||||||
|
* being wrapped in another implicit `Intent` that gets started.
|
||||||
|
*/
|
||||||
|
module ImplicitPendingIntentStartConfig implements DataFlow::StateConfigSig {
|
||||||
|
class FlowState = DataFlow::FlowState;
|
||||||
|
|
||||||
|
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||||
|
source.(ImplicitPendingIntentSource).hasState(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||||
|
sink.(ImplicitPendingIntentSink).hasState(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof ExplicitIntentSanitizer }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
any(ImplicitPendingIntentAdditionalTaintStep c).step(node1, node2)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||||
|
) {
|
||||||
|
any(ImplicitPendingIntentAdditionalTaintStep c).step(node1, state1, node2, state2)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
|
isSink(node, _) and
|
||||||
|
allowIntentExtrasImplicitRead(node, c)
|
||||||
|
or
|
||||||
|
isAdditionalFlowStep(node, _) and
|
||||||
|
c.(DataFlow::FieldContent).getType() instanceof PendingIntent
|
||||||
|
or
|
||||||
|
// Allow implicit reads of Intent arrays for steps like getActivities
|
||||||
|
// or sinks like startActivities
|
||||||
|
(isSink(node, _) or isAdditionalFlowStep(node, _, _, _)) and
|
||||||
|
node.getType().(Array).getElementType() instanceof TypeIntent and
|
||||||
|
c instanceof DataFlow::ArrayContent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module ImplicitPendingIntentStartFlow =
|
||||||
|
TaintTracking::GlobalWithState<ImplicitPendingIntentStartConfig>;
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import semmle.code.java.security.InsecureBasicAuth
|
|||||||
import semmle.code.java.dataflow.TaintTracking
|
import semmle.code.java.dataflow.TaintTracking
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `InsecureBasicAuthFlow` instead.
|
||||||
|
*
|
||||||
* A taint tracking configuration for the Basic authentication scheme
|
* A taint tracking configuration for the Basic authentication scheme
|
||||||
* being used in HTTP connections.
|
* being used in HTTP connections.
|
||||||
*/
|
*/
|
||||||
class BasicAuthFlowConfig extends TaintTracking::Configuration {
|
deprecated class BasicAuthFlowConfig extends TaintTracking::Configuration {
|
||||||
BasicAuthFlowConfig() { this = "InsecureBasicAuth::BasicAuthFlowConfig" }
|
BasicAuthFlowConfig() { this = "InsecureBasicAuth::BasicAuthFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src instanceof InsecureBasicAuthSource }
|
override predicate isSource(DataFlow::Node src) { src instanceof InsecureBasicAuthSource }
|
||||||
@@ -20,3 +22,22 @@ class BasicAuthFlowConfig extends TaintTracking::Configuration {
|
|||||||
any(HttpUrlsAdditionalTaintStep c).step(node1, node2)
|
any(HttpUrlsAdditionalTaintStep c).step(node1, node2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint tracking configuration for the Basic authentication scheme
|
||||||
|
* being used in HTTP connections.
|
||||||
|
*/
|
||||||
|
module BasicAuthFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src instanceof InsecureBasicAuthSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureBasicAuthSink }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
any(HttpUrlsAdditionalTaintStep c).step(node1, node2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks flow for the Basic authentication scheme being used in HTTP connections.
|
||||||
|
*/
|
||||||
|
module InsecureBasicAuthFlow = TaintTracking::Global<BasicAuthFlowConfig>;
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import semmle.code.java.dataflow.FlowSources
|
|||||||
import semmle.code.java.security.InsecureTrustManager
|
import semmle.code.java.security.InsecureTrustManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `InsecureTrustManagerFlow` instead.
|
||||||
|
*
|
||||||
* A configuration to model the flow of an insecure `TrustManager`
|
* A configuration to model the flow of an insecure `TrustManager`
|
||||||
* to the initialization of an SSL context.
|
* to the initialization of an SSL context.
|
||||||
*/
|
*/
|
||||||
class InsecureTrustManagerConfiguration extends DataFlow::Configuration {
|
deprecated class InsecureTrustManagerConfiguration extends DataFlow::Configuration {
|
||||||
InsecureTrustManagerConfiguration() { this = "InsecureTrustManagerConfiguration" }
|
InsecureTrustManagerConfiguration() { this = "InsecureTrustManagerConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
override predicate isSource(DataFlow::Node source) {
|
||||||
@@ -23,3 +25,21 @@ class InsecureTrustManagerConfiguration extends DataFlow::Configuration {
|
|||||||
c instanceof DataFlow::ArrayContent
|
c instanceof DataFlow::ArrayContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration to model the flow of an insecure `TrustManager`
|
||||||
|
* to the initialization of an SSL context.
|
||||||
|
*/
|
||||||
|
module InsecureTrustManagerConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof InsecureTrustManagerSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureTrustManagerSink }
|
||||||
|
|
||||||
|
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
|
(isSink(node) or isAdditionalFlowStep(node, _)) and
|
||||||
|
node.getType() instanceof Array and
|
||||||
|
c instanceof DataFlow::ArrayContent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module InsecureTrustManagerFlow = DataFlow::Global<InsecureTrustManagerConfig>;
|
||||||
|
|||||||
@@ -3,8 +3,12 @@
|
|||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.security.InsufficientKeySize
|
import semmle.code.java.security.InsufficientKeySize
|
||||||
|
|
||||||
/** A data flow configuration for tracking key sizes used in cryptographic algorithms. */
|
/**
|
||||||
class KeySizeConfiguration extends DataFlow::Configuration {
|
* DEPRECATED: Use `KeySizeFlow` instead.
|
||||||
|
*
|
||||||
|
* A data flow configuration for tracking key sizes used in cryptographic algorithms.
|
||||||
|
*/
|
||||||
|
deprecated class KeySizeConfiguration extends DataFlow::Configuration {
|
||||||
KeySizeConfiguration() { this = "KeySizeConfiguration" }
|
KeySizeConfiguration() { this = "KeySizeConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||||
@@ -15,3 +19,30 @@ class KeySizeConfiguration extends DataFlow::Configuration {
|
|||||||
sink.(InsufficientKeySizeSink).hasState(state)
|
sink.(InsufficientKeySizeSink).hasState(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data flow configuration for tracking key sizes used in cryptographic algorithms.
|
||||||
|
*/
|
||||||
|
module KeySizeConfig implements DataFlow::StateConfigSig {
|
||||||
|
class FlowState = DataFlow::FlowState;
|
||||||
|
|
||||||
|
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||||
|
source.(InsufficientKeySizeSource).hasState(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||||
|
sink.(InsufficientKeySizeSink).hasState(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tracks key sizes used in cryptographic algorithms. */
|
||||||
|
module KeySizeFlow = DataFlow::GlobalWithState<KeySizeConfig>;
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ deprecated class IntentUriPermissionManipulationConf extends TaintTracking::Conf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module IntentUriPermissionManipulationConfig implements DataFlow::ConfigSig {
|
/**
|
||||||
|
* A taint tracking configuration for user-provided Intents being returned to third party apps.
|
||||||
|
*/
|
||||||
|
module IntentUriPermissionManipulationConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) { sink instanceof IntentUriPermissionManipulationSink }
|
predicate isSink(DataFlow::Node sink) { sink instanceof IntentUriPermissionManipulationSink }
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ deprecated class LogInjectionConfiguration extends TaintTracking::Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module LogInjectionConfig implements DataFlow::ConfigSig {
|
/**
|
||||||
|
* A taint-tracking configuration for tracking untrusted user input used in log entries.
|
||||||
|
*/
|
||||||
|
module LogInjectionConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) { sink instanceof LogInjectionSink }
|
predicate isSink(DataFlow::Node sink) { sink instanceof LogInjectionSink }
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import semmle.code.java.dataflow.DataFlow
|
|||||||
import semmle.code.java.security.JWT
|
import semmle.code.java.security.JWT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `MissingJwtSignatureCheckFlow` instead.
|
||||||
|
*
|
||||||
* Models flow from signing keys assignments to qualifiers of JWT insecure parsers.
|
* Models flow from signing keys assignments to qualifiers of JWT insecure parsers.
|
||||||
* This is used to determine whether a `JwtParser` performing unsafe parsing has a signing key set.
|
* This is used to determine whether a `JwtParser` performing unsafe parsing has a signing key set.
|
||||||
*/
|
*/
|
||||||
class MissingJwtSignatureCheckConf extends DataFlow::Configuration {
|
deprecated class MissingJwtSignatureCheckConf extends DataFlow::Configuration {
|
||||||
MissingJwtSignatureCheckConf() { this = "SigningToExprDataFlow" }
|
MissingJwtSignatureCheckConf() { this = "SigningToExprDataFlow" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
override predicate isSource(DataFlow::Node source) {
|
||||||
@@ -21,3 +23,19 @@ class MissingJwtSignatureCheckConf extends DataFlow::Configuration {
|
|||||||
any(JwtParserWithInsecureParseAdditionalFlowStep c).step(node1, node2)
|
any(JwtParserWithInsecureParseAdditionalFlowStep c).step(node1, node2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models flow from signing keys assignments to qualifiers of JWT insecure parsers.
|
||||||
|
* This is used to determine whether a `JwtParser` performing unsafe parsing has a signing key set.
|
||||||
|
*/
|
||||||
|
module MissingJwtSignatureCheckConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof JwtParserWithInsecureParseSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof JwtParserWithInsecureParseSink }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
any(JwtParserWithInsecureParseAdditionalFlowStep c).step(node1, node2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module MissingJwtSignatureCheckFlow = DataFlow::Global<MissingJwtSignatureCheckConfig>;
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ import semmle.code.java.dataflow.TaintTracking
|
|||||||
import semmle.code.java.dataflow.FlowSources
|
import semmle.code.java.dataflow.FlowSources
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `PartialPathTraversalFromRemoteFlow` instead.
|
||||||
|
*
|
||||||
* A taint-tracking configuration for unsafe user input
|
* A taint-tracking configuration for unsafe user input
|
||||||
* that is used to validate against path traversal, but is insufficient
|
* that is used to validate against path traversal, but is insufficient
|
||||||
* and remains vulnerable to Partial Path Traversal.
|
* and remains vulnerable to Partial Path Traversal.
|
||||||
*/
|
*/
|
||||||
class PartialPathTraversalFromRemoteConfig extends TaintTracking::Configuration {
|
deprecated class PartialPathTraversalFromRemoteConfig extends TaintTracking::Configuration {
|
||||||
PartialPathTraversalFromRemoteConfig() { this = "PartialPathTraversalFromRemoteConfig" }
|
PartialPathTraversalFromRemoteConfig() { this = "PartialPathTraversalFromRemoteConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
|
override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
|
||||||
@@ -20,3 +22,20 @@ class PartialPathTraversalFromRemoteConfig extends TaintTracking::Configuration
|
|||||||
any(PartialPathTraversalMethodAccess ma).getQualifier() = node.asExpr()
|
any(PartialPathTraversalMethodAccess ma).getQualifier() = node.asExpr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint-tracking configuration for unsafe user input
|
||||||
|
* that is used to validate against path traversal, but is insufficient
|
||||||
|
* and remains vulnerable to Partial Path Traversal.
|
||||||
|
*/
|
||||||
|
module PartialPathTraversalFromRemoteConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node node) {
|
||||||
|
any(PartialPathTraversalMethodAccess ma).getQualifier() = node.asExpr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tracks flow of unsafe user input that is used to validate against path traversal, but is insufficient and remains vulnerable to Partial Path Traversal. */
|
||||||
|
module PartialPathTraversalFromRemoteFlow =
|
||||||
|
TaintTracking::Global<PartialPathTraversalFromRemoteConfig>;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DefUse
|
import semmle.code.java.dataflow.DefUse
|
||||||
import semmle.code.java.dataflow.DataFlow6
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import RandomDataSource
|
import RandomDataSource
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,20 +29,18 @@ private predicate isSeeded(RValue use) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PredictableSeedFlowConfiguration extends DataFlow6::Configuration {
|
private module PredictableSeedFlowConfig implements DataFlow::ConfigSig {
|
||||||
PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" }
|
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PredictableSeedExpr }
|
||||||
|
|
||||||
override predicate isSource(DataFlow6::Node source) {
|
predicate isSink(DataFlow::Node sink) { isSeeding(sink.asExpr(), _) }
|
||||||
source.asExpr() instanceof PredictableSeedExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow6::Node sink) { isSeeding(sink.asExpr(), _) }
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(DataFlow6::Node node1, DataFlow6::Node node2) {
|
|
||||||
predictableCalcStep(node1.asExpr(), node2.asExpr())
|
predictableCalcStep(node1.asExpr(), node2.asExpr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module PredictableSeedFlow = DataFlow::Global<PredictableSeedFlowConfig>;
|
||||||
|
|
||||||
private predicate predictableCalcStep(Expr e1, Expr e2) {
|
private predicate predictableCalcStep(Expr e1, Expr e2) {
|
||||||
e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p))
|
e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p))
|
||||||
or
|
or
|
||||||
@@ -81,7 +79,7 @@ private predicate predictableCalcStep(Expr e1, Expr e2) {
|
|||||||
private predicate safelySeeded(RValue use) {
|
private predicate safelySeeded(RValue use) {
|
||||||
exists(Expr arg |
|
exists(Expr arg |
|
||||||
isSeeding(arg, use) and
|
isSeeding(arg, use) and
|
||||||
not exists(PredictableSeedFlowConfiguration conf | conf.hasFlowToExpr(arg))
|
not PredictableSeedFlow::flowToExpr(arg)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(GetRandomData da, RValue seeduse |
|
exists(GetRandomData da, RValue seeduse |
|
||||||
@@ -118,9 +116,7 @@ private predicate isSeeding(Expr arg, RValue use) {
|
|||||||
|
|
||||||
private predicate isSeedingSource(Expr arg, RValue use, Expr source) {
|
private predicate isSeedingSource(Expr arg, RValue use, Expr source) {
|
||||||
isSeeding(arg, use) and
|
isSeeding(arg, use) and
|
||||||
exists(PredictableSeedFlowConfiguration conf |
|
PredictableSeedFlow::flow(DataFlow::exprNode(source), DataFlow::exprNode(arg))
|
||||||
conf.hasFlow(DataFlow6::exprNode(source), DataFlow6::exprNode(arg))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate isRandomSeeding(MethodAccess m, Expr arg) {
|
private predicate isRandomSeeding(MethodAccess m, Expr arg) {
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ deprecated class RsaWithoutOaepConfig extends DataFlow::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module RsaWithoutOaepConfig implements DataFlow::ConfigSig {
|
/**
|
||||||
|
* A configuration for finding RSA ciphers initialized without using OAEP padding.
|
||||||
|
*/
|
||||||
|
module RsaWithoutOaepConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node src) {
|
predicate isSource(DataFlow::Node src) {
|
||||||
exists(CompileTimeConstantExpr specExpr, string spec |
|
exists(CompileTimeConstantExpr specExpr, string spec |
|
||||||
specExpr.getStringValue() = spec and
|
specExpr.getStringValue() = spec and
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ deprecated class SensitiveLoggerConfiguration extends TaintTracking::Configurati
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
|
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
|
||||||
private module SensitiveLoggerConfig implements DataFlow::ConfigSig {
|
module SensitiveLoggerConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
|
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "logging") }
|
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "logging") }
|
||||||
|
|||||||
@@ -83,25 +83,23 @@ private class ArrayUpdate extends Expr {
|
|||||||
/**
|
/**
|
||||||
* A config that tracks dataflow from creating an array to an operation that updates it.
|
* A config that tracks dataflow from creating an array to an operation that updates it.
|
||||||
*/
|
*/
|
||||||
private class ArrayUpdateConfig extends DataFlow2::Configuration {
|
private module ArrayUpdateConfig implements DataFlow::ConfigSig {
|
||||||
ArrayUpdateConfig() { this = "ArrayUpdateConfig" }
|
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof StaticByteArrayCreation }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(ArrayUpdate upd).getArray() }
|
||||||
source.asExpr() instanceof StaticByteArrayCreation
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(ArrayUpdate upd).getArray() }
|
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||||
|
|
||||||
override predicate isBarrierOut(DataFlow::Node node) { this.isSink(node) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module ArrayUpdateFlow = DataFlow::Global<ArrayUpdateConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A source that defines an array that doesn't get updated.
|
* A source that defines an array that doesn't get updated.
|
||||||
*/
|
*/
|
||||||
private class StaticInitializationVectorSource extends DataFlow::Node {
|
private class StaticInitializationVectorSource extends DataFlow::Node {
|
||||||
StaticInitializationVectorSource() {
|
StaticInitializationVectorSource() {
|
||||||
exists(StaticByteArrayCreation array | array = this.asExpr() |
|
exists(StaticByteArrayCreation array | array = this.asExpr() |
|
||||||
not exists(ArrayUpdateConfig config | config.hasFlow(DataFlow2::exprNode(array), _)) and
|
not ArrayUpdateFlow::flow(DataFlow2::exprNode(array), _) and
|
||||||
// Reduce FPs from utility methods that return an empty array in an exceptional case
|
// Reduce FPs from utility methods that return an empty array in an exceptional case
|
||||||
not exists(ReturnStmt ret |
|
not exists(ReturnStmt ret |
|
||||||
array.getADimension().(CompileTimeConstantExpr).getIntValue() = 0 and
|
array.getADimension().(CompileTimeConstantExpr).getIntValue() = 0 and
|
||||||
@@ -146,9 +144,11 @@ private predicate createInitializationVectorSpecStep(DataFlow::Node fromNode, Da
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `StaticInitializationVectorFlow` instead.
|
||||||
|
*
|
||||||
* A config that tracks dataflow to initializing a cipher with a static initialization vector.
|
* A config that tracks dataflow to initializing a cipher with a static initialization vector.
|
||||||
*/
|
*/
|
||||||
class StaticInitializationVectorConfig extends TaintTracking::Configuration {
|
deprecated class StaticInitializationVectorConfig extends TaintTracking::Configuration {
|
||||||
StaticInitializationVectorConfig() { this = "StaticInitializationVectorConfig" }
|
StaticInitializationVectorConfig() { this = "StaticInitializationVectorConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
override predicate isSource(DataFlow::Node source) {
|
||||||
@@ -161,3 +161,19 @@ class StaticInitializationVectorConfig extends TaintTracking::Configuration {
|
|||||||
createInitializationVectorSpecStep(fromNode, toNode)
|
createInitializationVectorSpecStep(fromNode, toNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A config that tracks dataflow to initializing a cipher with a static initialization vector.
|
||||||
|
*/
|
||||||
|
module StaticInitializationVectorConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof StaticInitializationVectorSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof EncryptionInitializationSink }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||||
|
createInitializationVectorSpecStep(fromNode, toNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tracks the flow from a static initialization vector to the initialization of a cipher */
|
||||||
|
module StaticInitializationVectorFlow = TaintTracking::Global<StaticInitializationVectorConfig>;
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import semmle.code.java.security.UnsafeCertTrust
|
|||||||
import semmle.code.java.security.Encryption
|
import semmle.code.java.security.Encryption
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `SslEndpointIdentificationFlow` instead.
|
||||||
|
*
|
||||||
* A taint flow configuration for SSL connections created without a proper certificate trust configuration.
|
* A taint flow configuration for SSL connections created without a proper certificate trust configuration.
|
||||||
*/
|
*/
|
||||||
class SslEndpointIdentificationFlowConfig extends TaintTracking::Configuration {
|
deprecated class SslEndpointIdentificationFlowConfig extends TaintTracking::Configuration {
|
||||||
SslEndpointIdentificationFlowConfig() { this = "SslEndpointIdentificationFlowConfig" }
|
SslEndpointIdentificationFlowConfig() { this = "SslEndpointIdentificationFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof SslConnectionInit }
|
override predicate isSource(DataFlow::Node source) { source instanceof SslConnectionInit }
|
||||||
@@ -20,30 +22,44 @@ class SslEndpointIdentificationFlowConfig extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taint flow configuration for SSL connections created without a proper certificate trust configuration.
|
||||||
|
*/
|
||||||
|
module SslEndpointIdentificationFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof SslConnectionInit }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof SslConnectionCreation }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof SslUnsafeCertTrustSanitizer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taint flow for SSL connections created without a proper certificate trust configuration.
|
||||||
|
*/
|
||||||
|
module SslEndpointIdentificationFlow = TaintTracking::Global<SslEndpointIdentificationFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An SSL object that was assigned a safe `SSLParameters` object and can be considered safe.
|
* An SSL object that was assigned a safe `SSLParameters` object and can be considered safe.
|
||||||
*/
|
*/
|
||||||
private class SslConnectionWithSafeSslParameters extends SslUnsafeCertTrustSanitizer {
|
private class SslConnectionWithSafeSslParameters extends SslUnsafeCertTrustSanitizer {
|
||||||
SslConnectionWithSafeSslParameters() {
|
SslConnectionWithSafeSslParameters() {
|
||||||
exists(SafeSslParametersFlowConfig config, DataFlow::Node safe, DataFlow::Node sanitizer |
|
exists(DataFlow::Node safe, DataFlow::Node sanitizer |
|
||||||
config.hasFlowTo(safe) and
|
SafeSslParametersFlow::flowTo(safe) and
|
||||||
sanitizer = DataFlow::exprNode(safe.asExpr().(Argument).getCall().getQualifier()) and
|
sanitizer = DataFlow::exprNode(safe.asExpr().(Argument).getCall().getQualifier()) and
|
||||||
DataFlow::localFlow(sanitizer, this)
|
DataFlow::localFlow(sanitizer, this)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeSslParametersFlowConfig extends DataFlow2::Configuration {
|
private module SafeSslParametersFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeSslParametersFlowConfig() { this = "SafeSslParametersFlowConfig" }
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
ma instanceof SafeSetEndpointIdentificationAlgorithm and
|
ma instanceof SafeSetEndpointIdentificationAlgorithm and
|
||||||
DataFlow::getInstanceArgument(ma) = source.(DataFlow::PostUpdateNode).getPreUpdateNode()
|
DataFlow::getInstanceArgument(ma) = source.(DataFlow::PostUpdateNode).getPreUpdateNode()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(MethodAccess ma, RefType t | t instanceof SslSocket or t instanceof SslEngine |
|
exists(MethodAccess ma, RefType t | t instanceof SslSocket or t instanceof SslEngine |
|
||||||
ma.getMethod().hasName("setSSLParameters") and
|
ma.getMethod().hasName("setSSLParameters") and
|
||||||
ma.getMethod().getDeclaringType().getAnAncestor() = t and
|
ma.getMethod().getDeclaringType().getAnAncestor() = t and
|
||||||
@@ -52,6 +68,8 @@ private class SafeSslParametersFlowConfig extends DataFlow2::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeSslParametersFlow = DataFlow::Global<SafeSslParametersFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A call to `SSLParameters.setEndpointIdentificationAlgorithm` with a non-null and non-empty parameter.
|
* A call to `SSLParameters.setEndpointIdentificationAlgorithm` with a non-null and non-empty parameter.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ deprecated class UnsafeContentResolutionConf extends TaintTracking::Configuratio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module UnsafeContentResolutionConfig implements DataFlow::ConfigSig {
|
/**
|
||||||
|
* A taint-tracking configuration to find paths from remote sources to content URI resolutions.
|
||||||
|
*/
|
||||||
|
module UnsafeContentResolutionConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) { sink instanceof ContentUriResolutionSink }
|
predicate isSink(DataFlow::Node sink) { sink instanceof ContentUriResolutionSink }
|
||||||
|
|||||||
@@ -35,15 +35,13 @@ private class XmlDecoderReadObjectMethod extends Method {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeXStream extends DataFlow2::Configuration {
|
private module SafeXStreamConfig implements DataFlow::ConfigSig {
|
||||||
SafeXStream() { this = "UnsafeDeserialization::SafeXStream" }
|
predicate isSource(DataFlow::Node src) {
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
|
||||||
any(XStreamEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
any(XStreamEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
||||||
src.asExpr()
|
src.asExpr()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
sink.asExpr() = ma.getQualifier() and
|
sink.asExpr() = ma.getQualifier() and
|
||||||
ma.getMethod() instanceof XStreamReadObjectMethod
|
ma.getMethod() instanceof XStreamReadObjectMethod
|
||||||
@@ -51,26 +49,26 @@ private class SafeXStream extends DataFlow2::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeKryo extends DataFlow2::Configuration {
|
private module SafeXStreamFlow = DataFlow::Global<SafeXStreamConfig>;
|
||||||
SafeKryo() { this = "UnsafeDeserialization::SafeKryo" }
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
private module SafeKryoConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) {
|
||||||
any(KryoEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
any(KryoEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
||||||
src.asExpr()
|
src.asExpr()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
sink.asExpr() = ma.getQualifier() and
|
sink.asExpr() = ma.getQualifier() and
|
||||||
ma.getMethod() instanceof KryoReadObjectMethod
|
ma.getMethod() instanceof KryoReadObjectMethod
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
this.stepKryoPoolBuilderFactoryArgToConstructor(node1, node2) or
|
stepKryoPoolBuilderFactoryArgToConstructor(node1, node2) or
|
||||||
this.stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(node1, node2) or
|
stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(node1, node2) or
|
||||||
this.stepKryoPoolBuilderChainMethod(node1, node2) or
|
stepKryoPoolBuilderChainMethod(node1, node2) or
|
||||||
this.stepKryoPoolBorrowMethod(node1, node2)
|
stepKryoPoolBorrowMethod(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,6 +124,8 @@ private class SafeKryo extends DataFlow2::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeKryoFlow = DataFlow::Global<SafeKryoConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `ma` is a call that deserializes data from `sink`.
|
* Holds if `ma` is a call that deserializes data from `sink`.
|
||||||
*/
|
*/
|
||||||
@@ -145,11 +145,11 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
|||||||
or
|
or
|
||||||
m instanceof XStreamReadObjectMethod and
|
m instanceof XStreamReadObjectMethod and
|
||||||
sink = ma.getAnArgument() and
|
sink = ma.getAnArgument() and
|
||||||
not exists(SafeXStream sxs | sxs.hasFlowToExpr(ma.getQualifier()))
|
not SafeXStreamFlow::flowToExpr(ma.getQualifier())
|
||||||
or
|
or
|
||||||
m instanceof KryoReadObjectMethod and
|
m instanceof KryoReadObjectMethod and
|
||||||
sink = ma.getAnArgument() and
|
sink = ma.getAnArgument() and
|
||||||
not exists(SafeKryo sk | sk.hasFlowToExpr(ma.getQualifier()))
|
not SafeKryoFlow::flowToExpr(ma.getQualifier())
|
||||||
or
|
or
|
||||||
m instanceof MethodApacheSerializationUtilsDeserialize and
|
m instanceof MethodApacheSerializationUtilsDeserialize and
|
||||||
sink = ma.getArgument(0)
|
sink = ma.getArgument(0)
|
||||||
@@ -181,17 +181,17 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
|||||||
ma.getMethod() instanceof ObjectMapperReadMethod and
|
ma.getMethod() instanceof ObjectMapperReadMethod and
|
||||||
sink = ma.getArgument(0) and
|
sink = ma.getArgument(0) and
|
||||||
(
|
(
|
||||||
exists(UnsafeTypeConfig config | config.hasFlowToExpr(ma.getAnArgument()))
|
UnsafeTypeFlow::flowToExpr(ma.getAnArgument())
|
||||||
or
|
or
|
||||||
exists(EnableJacksonDefaultTypingConfig config | config.hasFlowToExpr(ma.getQualifier()))
|
EnableJacksonDefaultTypingFlow::flowToExpr(ma.getQualifier())
|
||||||
or
|
or
|
||||||
hasArgumentWithUnsafeJacksonAnnotation(ma)
|
hasArgumentWithUnsafeJacksonAnnotation(ma)
|
||||||
) and
|
) and
|
||||||
not exists(SafeObjectMapperConfig config | config.hasFlowToExpr(ma.getQualifier()))
|
not SafeObjectMapperFlow::flowToExpr(ma.getQualifier())
|
||||||
or
|
or
|
||||||
m instanceof JabsorbUnmarshallMethod and
|
m instanceof JabsorbUnmarshallMethod and
|
||||||
sink = ma.getArgument(2) and
|
sink = ma.getArgument(2) and
|
||||||
any(UnsafeTypeConfig config).hasFlowToExpr(ma.getArgument(1))
|
UnsafeTypeFlow::flowToExpr(ma.getArgument(1))
|
||||||
or
|
or
|
||||||
m instanceof JabsorbFromJsonMethod and
|
m instanceof JabsorbFromJsonMethod and
|
||||||
sink = ma.getArgument(0)
|
sink = ma.getArgument(0)
|
||||||
@@ -200,7 +200,7 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
|||||||
sink = ma.getArgument(0) and
|
sink = ma.getArgument(0) and
|
||||||
(
|
(
|
||||||
// User controls the target type for deserialization
|
// User controls the target type for deserialization
|
||||||
any(UnsafeTypeConfig c).hasFlowToExpr(ma.getArgument(1))
|
UnsafeTypeFlow::flowToExpr(ma.getArgument(1))
|
||||||
or
|
or
|
||||||
// jodd.json.JsonParser may be configured for unrestricted deserialization to user-specified types
|
// jodd.json.JsonParser may be configured for unrestricted deserialization to user-specified types
|
||||||
joddJsonParserConfiguredUnsafely(ma.getQualifier())
|
joddJsonParserConfiguredUnsafely(ma.getQualifier())
|
||||||
@@ -211,7 +211,7 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
|||||||
or
|
or
|
||||||
m instanceof GsonDeserializeMethod and
|
m instanceof GsonDeserializeMethod and
|
||||||
sink = ma.getArgument(0) and
|
sink = ma.getArgument(0) and
|
||||||
any(UnsafeTypeConfig config).hasFlowToExpr(ma.getArgument(1))
|
UnsafeTypeFlow::flowToExpr(ma.getArgument(1))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,52 +223,18 @@ class UnsafeDeserializationSink extends DataFlow::ExprNode {
|
|||||||
MethodAccess getMethodAccess() { unsafeDeserialization(result, this.getExpr()) }
|
MethodAccess getMethodAccess() { unsafeDeserialization(result, this.getExpr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Holds if `node` is a sanitizer for unsafe deserialization */
|
||||||
* Tracks flows from remote user input to a deserialization sink.
|
private predicate isUnsafeDeserializationSanitizer(DataFlow::Node node) {
|
||||||
*/
|
|
||||||
class UnsafeDeserializationConfig extends TaintTracking::Configuration {
|
|
||||||
UnsafeDeserializationConfig() { this = "UnsafeDeserializationConfig" }
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
|
|
||||||
|
|
||||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
|
||||||
exists(ClassInstanceExpr cie |
|
|
||||||
cie.getArgument(0) = pred.asExpr() and
|
|
||||||
cie = succ.asExpr() and
|
|
||||||
(
|
|
||||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
|
|
||||||
cie.getConstructor().getDeclaringType() instanceof YamlBeansReader or
|
|
||||||
cie.getConstructor().getDeclaringType().getAnAncestor() instanceof UnsafeHessianInput or
|
|
||||||
cie.getConstructor().getDeclaringType() instanceof BurlapInput
|
|
||||||
)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(MethodAccess ma |
|
|
||||||
ma.getMethod() instanceof BurlapInputInitMethod and
|
|
||||||
ma.getArgument(0) = pred.asExpr() and
|
|
||||||
ma.getQualifier() = succ.asExpr()
|
|
||||||
)
|
|
||||||
or
|
|
||||||
createJacksonJsonParserStep(pred, succ)
|
|
||||||
or
|
|
||||||
createJacksonTreeNodeStep(pred, succ)
|
|
||||||
or
|
|
||||||
intentFlowsToParcel(pred, succ)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node node) {
|
|
||||||
exists(ClassInstanceExpr cie |
|
exists(ClassInstanceExpr cie |
|
||||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
|
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
|
||||||
cie = node.asExpr() and
|
cie = node.asExpr() and
|
||||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(cie.getArgument(1)))
|
SafeJsonIoFlow::flowToExpr(cie.getArgument(1))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||||
ma.getArgument(0) = node.asExpr() and
|
ma.getArgument(0) = node.asExpr() and
|
||||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(ma.getArgument(1)))
|
SafeJsonIoFlow::flowToExpr(ma.getArgument(1))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
@@ -297,9 +263,68 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
|
|||||||
isSafeFlexjsonDeserializer(ma.getQualifier())
|
isSafeFlexjsonDeserializer(ma.getQualifier())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Taint step for Unsafe deserialization */
|
||||||
|
private predicate isUnsafeDeserializationTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
exists(ClassInstanceExpr cie |
|
||||||
|
cie.getArgument(0) = pred.asExpr() and
|
||||||
|
cie = succ.asExpr() and
|
||||||
|
(
|
||||||
|
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
|
||||||
|
cie.getConstructor().getDeclaringType() instanceof YamlBeansReader or
|
||||||
|
cie.getConstructor().getDeclaringType().getAnAncestor() instanceof UnsafeHessianInput or
|
||||||
|
cie.getConstructor().getDeclaringType() instanceof BurlapInput
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(MethodAccess ma |
|
||||||
|
ma.getMethod() instanceof BurlapInputInitMethod and
|
||||||
|
ma.getArgument(0) = pred.asExpr() and
|
||||||
|
ma.getQualifier() = succ.asExpr()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
createJacksonJsonParserStep(pred, succ)
|
||||||
|
or
|
||||||
|
createJacksonTreeNodeStep(pred, succ)
|
||||||
|
or
|
||||||
|
intentFlowsToParcel(pred, succ)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `UnsafeDeserializationFlow` instead.
|
||||||
|
*
|
||||||
|
* Tracks flows from remote user input to a deserialization sink.
|
||||||
|
*/
|
||||||
|
deprecated class UnsafeDeserializationConfig extends TaintTracking::Configuration {
|
||||||
|
UnsafeDeserializationConfig() { this = "UnsafeDeserializationConfig" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
|
||||||
|
|
||||||
|
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
isUnsafeDeserializationTaintStep(pred, succ)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSanitizer(DataFlow::Node node) { isUnsafeDeserializationSanitizer(node) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tracks flows from remote user input to a deserialization sink. */
|
||||||
|
private module UnsafeDeserializationConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
|
||||||
|
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
isUnsafeDeserializationTaintStep(pred, succ)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) { isUnsafeDeserializationSanitizer(node) }
|
||||||
|
}
|
||||||
|
|
||||||
|
module UnsafeDeserializationFlow = TaintTracking::Global<UnsafeDeserializationConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a safe usage of the `use` method of Flexjson, which could be:
|
* Gets a safe usage of the `use` method of Flexjson, which could be:
|
||||||
* use(String, ...) where the path is null or
|
* use(String, ...) where the path is null or
|
||||||
@@ -350,18 +375,9 @@ predicate looksLikeResolveClassStep(DataFlow::Node fromNode, DataFlow::Node toNo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** A sink representing an argument of a deserialization method */
|
||||||
* Tracks flow from a remote source to a type descriptor (e.g. a `java.lang.Class` instance)
|
private class UnsafeTypeSink extends DataFlow::Node {
|
||||||
* passed to a deserialization method.
|
UnsafeTypeSink() {
|
||||||
*
|
|
||||||
* If this is user-controlled, arbitrary code could be executed while instantiating the user-specified type.
|
|
||||||
*/
|
|
||||||
class UnsafeTypeConfig extends TaintTracking2::Configuration {
|
|
||||||
UnsafeTypeConfig() { this = "UnsafeTypeConfig" }
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(MethodAccess ma, int i, Expr arg | i > 0 and ma.getArgument(i) = arg |
|
exists(MethodAccess ma, int i, Expr arg | i > 0 and ma.getArgument(i) = arg |
|
||||||
(
|
(
|
||||||
ma.getMethod() instanceof ObjectMapperReadMethod
|
ma.getMethod() instanceof ObjectMapperReadMethod
|
||||||
@@ -378,25 +394,75 @@ class UnsafeTypeConfig extends TaintTracking2::Configuration {
|
|||||||
or
|
or
|
||||||
arg.getType().(RefType).hasQualifiedName("java.lang.reflect", "Type")
|
arg.getType().(RefType).hasQualifiedName("java.lang.reflect", "Type")
|
||||||
) and
|
) and
|
||||||
arg = sink.asExpr()
|
arg = this.asExpr()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isUnsafeTypeAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||||
|
resolveClassStep(fromNode, toNode) or
|
||||||
|
looksLikeResolveClassStep(fromNode, toNode) or
|
||||||
|
intentFlowsToParcel(fromNode, toNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `UnsafeTypeFlow` instead.
|
||||||
|
*
|
||||||
|
* Tracks flow from a remote source to a type descriptor (e.g. a `java.lang.Class` instance)
|
||||||
|
* passed to a deserialization method.
|
||||||
|
*
|
||||||
|
* If this is user-controlled, arbitrary code could be executed while instantiating the user-specified type.
|
||||||
|
*/
|
||||||
|
deprecated class UnsafeTypeConfig extends TaintTracking2::Configuration {
|
||||||
|
UnsafeTypeConfig() { this = "UnsafeTypeConfig" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeTypeSink }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `fromNode` to `toNode` is a dataflow step that resolves a class
|
* Holds if `fromNode` to `toNode` is a dataflow step that resolves a class
|
||||||
* or at least looks like resolving a class.
|
* or at least looks like resolving a class.
|
||||||
*/
|
*/
|
||||||
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||||
resolveClassStep(fromNode, toNode) or
|
isUnsafeTypeAdditionalTaintStep(fromNode, toNode)
|
||||||
looksLikeResolveClassStep(fromNode, toNode) or
|
|
||||||
intentFlowsToParcel(fromNode, toNode)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Tracks flow from a remote source to a type descriptor (e.g. a `java.lang.Class` instance)
|
||||||
|
* passed to a deserialization method.
|
||||||
|
*
|
||||||
|
* If this is user-controlled, arbitrary code could be executed while instantiating the user-specified type.
|
||||||
|
*/
|
||||||
|
module UnsafeTypeConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeTypeSink }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `fromNode` to `toNode` is a dataflow step that resolves a class
|
||||||
|
* or at least looks like resolving a class.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||||
|
isUnsafeTypeAdditionalTaintStep(fromNode, toNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks flow from a remote source to a type descriptor (e.g. a `java.lang.Class` instance)
|
||||||
|
* passed to a deserialization method.
|
||||||
|
*
|
||||||
|
* If this is user-controlled, arbitrary code could be executed while instantiating the user-specified type.
|
||||||
|
*/
|
||||||
|
module UnsafeTypeFlow = TaintTracking::Global<UnsafeTypeConfig>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `EnableJacksonDefaultTypingFlow` instead.
|
||||||
|
*
|
||||||
* Tracks flow from `enableDefaultTyping` calls to a subsequent Jackson deserialization method call.
|
* Tracks flow from `enableDefaultTyping` calls to a subsequent Jackson deserialization method call.
|
||||||
*/
|
*/
|
||||||
class EnableJacksonDefaultTypingConfig extends DataFlow2::Configuration {
|
deprecated class EnableJacksonDefaultTypingConfig extends DataFlow2::Configuration {
|
||||||
EnableJacksonDefaultTypingConfig() { this = "EnableJacksonDefaultTypingConfig" }
|
EnableJacksonDefaultTypingConfig() { this = "EnableJacksonDefaultTypingConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
override predicate isSource(DataFlow::Node src) {
|
||||||
@@ -406,13 +472,43 @@ class EnableJacksonDefaultTypingConfig extends DataFlow2::Configuration {
|
|||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ObjectMapperReadQualifier }
|
override predicate isSink(DataFlow::Node sink) { sink instanceof ObjectMapperReadQualifier }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module EnableJacksonDefaultTypingConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) {
|
||||||
|
any(EnableJacksonDefaultTyping ma).getQualifier() = src.asExpr()
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof ObjectMapperReadQualifier }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Tracks flow from `enableDefaultTyping` calls to a subsequent Jackson deserialization method call.
|
||||||
|
*/
|
||||||
|
module EnableJacksonDefaultTypingFlow = DataFlow::Global<EnableJacksonDefaultTypingConfig>;
|
||||||
|
|
||||||
|
/** Dataflow step that creates an `ObjectMapper` via a builder. */
|
||||||
|
private predicate isObjectMapperBuilderAdditionalFlowStep(
|
||||||
|
DataFlow::Node fromNode, DataFlow::Node toNode
|
||||||
|
) {
|
||||||
|
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||||
|
m.getDeclaringType() instanceof MapperBuilder and
|
||||||
|
m.getReturnType()
|
||||||
|
.(RefType)
|
||||||
|
.hasQualifiedName("com.fasterxml.jackson.databind.json",
|
||||||
|
["JsonMapper$Builder", "JsonMapper"]) and
|
||||||
|
fromNode.asExpr() = ma.getQualifier() and
|
||||||
|
ma = toNode.asExpr()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED: Use `SafeObjectMapperFlow` instead.
|
||||||
|
*
|
||||||
* Tracks flow from calls that set a type validator to a subsequent Jackson deserialization method call,
|
* Tracks flow from calls that set a type validator to a subsequent Jackson deserialization method call,
|
||||||
* including across builder method calls.
|
* including across builder method calls.
|
||||||
*
|
*
|
||||||
* Such a Jackson deserialization method call is safe because validation will likely prevent instantiating unexpected types.
|
* Such a Jackson deserialization method call is safe because validation will likely prevent instantiating unexpected types.
|
||||||
*/
|
*/
|
||||||
class SafeObjectMapperConfig extends DataFlow2::Configuration {
|
deprecated class SafeObjectMapperConfig extends DataFlow2::Configuration {
|
||||||
SafeObjectMapperConfig() { this = "SafeObjectMapperConfig" }
|
SafeObjectMapperConfig() { this = "SafeObjectMapperConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
override predicate isSource(DataFlow::Node src) {
|
||||||
@@ -426,18 +522,38 @@ class SafeObjectMapperConfig extends DataFlow2::Configuration {
|
|||||||
* that configures or creates an `ObjectMapper` via a builder.
|
* that configures or creates an `ObjectMapper` via a builder.
|
||||||
*/
|
*/
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
isObjectMapperBuilderAdditionalFlowStep(fromNode, toNode)
|
||||||
m.getDeclaringType() instanceof MapperBuilder and
|
|
||||||
m.getReturnType()
|
|
||||||
.(RefType)
|
|
||||||
.hasQualifiedName("com.fasterxml.jackson.databind.json",
|
|
||||||
["JsonMapper$Builder", "JsonMapper"]) and
|
|
||||||
fromNode.asExpr() = ma.getQualifier() and
|
|
||||||
ma = toNode.asExpr()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks flow from calls that set a type validator to a subsequent Jackson deserialization method call,
|
||||||
|
* including across builder method calls.
|
||||||
|
*
|
||||||
|
* Such a Jackson deserialization method call is safe because validation will likely prevent instantiating unexpected types.
|
||||||
|
*/
|
||||||
|
module SafeObjectMapperConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src instanceof SetPolymorphicTypeValidatorSource }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { sink instanceof ObjectMapperReadQualifier }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `fromNode` to `toNode` is a dataflow step
|
||||||
|
* that configures or creates an `ObjectMapper` via a builder.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||||
|
isObjectMapperBuilderAdditionalFlowStep(fromNode, toNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks flow from calls that set a type validator to a subsequent Jackson deserialization method call,
|
||||||
|
* including across builder method calls.
|
||||||
|
*
|
||||||
|
* Such a Jackson deserialization method call is safe because validation will likely prevent instantiating unexpected types.
|
||||||
|
*/
|
||||||
|
module SafeObjectMapperFlow = DataFlow::Global<SafeObjectMapperConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A method that configures Jodd's JsonParser, either enabling dangerous deserialization to
|
* A method that configures Jodd's JsonParser, either enabling dangerous deserialization to
|
||||||
* arbitrary Java types or restricting the types that can be instantiated.
|
* arbitrary Java types or restricting the types that can be instantiated.
|
||||||
@@ -454,20 +570,12 @@ private class JoddJsonParserConfigurationMethodQualifier extends DataFlow::ExprN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private module JoddJsonParserConfigurationMethodConfig implements DataFlow::ConfigSig {
|
||||||
* Configuration tracking flow from methods that configure `jodd.json.JsonParser`'s class
|
predicate isSource(DataFlow::Node src) {
|
||||||
* instantiation feature to a `.parse` call on the same parser.
|
|
||||||
*/
|
|
||||||
private class JoddJsonParserConfigurationMethodConfig extends DataFlow2::Configuration {
|
|
||||||
JoddJsonParserConfigurationMethodConfig() {
|
|
||||||
this = "UnsafeDeserialization::JoddJsonParserConfigurationMethodConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
|
||||||
src instanceof JoddJsonParserConfigurationMethodQualifier
|
src instanceof JoddJsonParserConfigurationMethodQualifier
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
ma.getMethod() instanceof JoddJsonParseMethod and
|
ma.getMethod() instanceof JoddJsonParseMethod and
|
||||||
sink.asExpr() = ma.getQualifier() // The class type argument
|
sink.asExpr() = ma.getQualifier() // The class type argument
|
||||||
@@ -475,6 +583,13 @@ private class JoddJsonParserConfigurationMethodConfig extends DataFlow2::Configu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration tracking flow from methods that configure `jodd.json.JsonParser`'s class
|
||||||
|
* instantiation feature to a `.parse` call on the same parser.
|
||||||
|
*/
|
||||||
|
private module JoddJsonParserConfigurationMethodFlow =
|
||||||
|
DataFlow::Global<JoddJsonParserConfigurationMethodConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the qualifier to a method call that configures a `jodd.json.JsonParser` instance unsafely.
|
* Gets the qualifier to a method call that configures a `jodd.json.JsonParser` instance unsafely.
|
||||||
*
|
*
|
||||||
@@ -512,10 +627,8 @@ private DataFlow::Node getASafelyConfiguredParser() {
|
|||||||
* and which never appears to be configured safely.
|
* and which never appears to be configured safely.
|
||||||
*/
|
*/
|
||||||
private predicate joddJsonParserConfiguredUnsafely(Expr parserExpr) {
|
private predicate joddJsonParserConfiguredUnsafely(Expr parserExpr) {
|
||||||
exists(DataFlow::Node parser, JoddJsonParserConfigurationMethodConfig config |
|
exists(DataFlow::Node parser | parser.asExpr() = parserExpr |
|
||||||
parser.asExpr() = parserExpr
|
JoddJsonParserConfigurationMethodFlow::flow(getAnUnsafelyConfiguredParser(), parser) and
|
||||||
|
|
not JoddJsonParserConfigurationMethodFlow::flow(getASafelyConfiguredParser(), parser)
|
||||||
config.hasFlow(getAnUnsafelyConfiguredParser(), parser) and
|
|
||||||
not config.hasFlow(getASafelyConfiguredParser(), parser)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,24 +81,18 @@ class DocumentBuilderParse extends XmlParserCall {
|
|||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() {
|
||||||
exists(SafeDocumentBuilderToDocumentBuilderParseFlowConfig conf |
|
SafeDocumentBuilderToDocumentBuilderParseFlow::flowToExpr(this.getQualifier())
|
||||||
conf.hasFlowToExpr(this.getQualifier())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeDocumentBuilderToDocumentBuilderParseFlowConfig extends DataFlow2::Configuration {
|
private module SafeDocumentBuilderToDocumentBuilderParseFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeDocumentBuilderToDocumentBuilderParseFlowConfig() {
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDocumentBuilder }
|
||||||
this = "XmlParsers::SafeDocumentBuilderToDocumentBuilderParseFlowConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDocumentBuilder }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
sink.asExpr() = any(DocumentBuilderParse dbp).getQualifier()
|
sink.asExpr() = any(DocumentBuilderParse dbp).getQualifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
exists(RefType t, ReturnStmt ret, Method m |
|
exists(RefType t, ReturnStmt ret, Method m |
|
||||||
node2.asExpr().(ClassInstanceExpr).getConstructedType().getSourceDeclaration() = t and
|
node2.asExpr().(ClassInstanceExpr).getConstructedType().getSourceDeclaration() = t and
|
||||||
t.getASourceSupertype+().hasQualifiedName("java.lang", "ThreadLocal") and
|
t.getASourceSupertype+().hasQualifiedName("java.lang", "ThreadLocal") and
|
||||||
@@ -117,9 +111,12 @@ private class SafeDocumentBuilderToDocumentBuilderParseFlowConfig extends DataFl
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeDocumentBuilderToDocumentBuilderParseFlow =
|
||||||
|
DataFlow::Global<SafeDocumentBuilderToDocumentBuilderParseFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `ParserConfig` specific to `DocumentBuilderFactory`.
|
* A `ParserConfig` specific to `DocumentBuilderFactory`.
|
||||||
*/
|
*/
|
||||||
@@ -198,31 +195,27 @@ private class DocumentBuilderConstruction extends MethodAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig extends DataFlow3::Configuration
|
private module SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig implements
|
||||||
|
DataFlow::ConfigSig
|
||||||
{
|
{
|
||||||
SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig() {
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDocumentBuilderFactory }
|
||||||
this = "XmlParsers::SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
src.asExpr() instanceof SafeDocumentBuilderFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
sink.asExpr() = any(DocumentBuilderConstruction dbc).getQualifier()
|
sink.asExpr() = any(DocumentBuilderConstruction dbc).getQualifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlow =
|
||||||
|
DataFlow::Global<SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `DocumentBuilder` created from a safely configured `DocumentBuilderFactory`.
|
* A `DocumentBuilder` created from a safely configured `DocumentBuilderFactory`.
|
||||||
*/
|
*/
|
||||||
class SafeDocumentBuilder extends DocumentBuilderConstruction {
|
class SafeDocumentBuilder extends DocumentBuilderConstruction {
|
||||||
SafeDocumentBuilder() {
|
SafeDocumentBuilder() {
|
||||||
exists(SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig conf |
|
SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlow::flowToExpr(this.getQualifier())
|
||||||
conf.hasFlowToExpr(this.getQualifier())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,27 +245,24 @@ class XmlInputFactoryStreamReader extends XmlParserCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() {
|
||||||
exists(SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig conf |
|
SafeXmlInputFactoryToXmlInputFactoryReaderFlow::flowToExpr(this.getQualifier())
|
||||||
conf.hasFlowToExpr(this.getQualifier())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig extends DataFlow2::Configuration {
|
private module SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig() {
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeXmlInputFactory }
|
||||||
this = "XmlParsers::SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeXmlInputFactory }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
sink.asExpr() = any(XmlInputFactoryStreamReader xifsr).getQualifier() or
|
sink.asExpr() = any(XmlInputFactoryStreamReader xifsr).getQualifier() or
|
||||||
sink.asExpr() = any(XmlInputFactoryEventReader xifer).getQualifier()
|
sink.asExpr() = any(XmlInputFactoryEventReader xifer).getQualifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeXmlInputFactoryToXmlInputFactoryReaderFlow =
|
||||||
|
DataFlow::Global<SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig>;
|
||||||
|
|
||||||
/** A call to `XMLInputFactory.createEventReader`. */
|
/** A call to `XMLInputFactory.createEventReader`. */
|
||||||
class XmlInputFactoryEventReader extends XmlParserCall {
|
class XmlInputFactoryEventReader extends XmlParserCall {
|
||||||
XmlInputFactoryEventReader() {
|
XmlInputFactoryEventReader() {
|
||||||
@@ -290,9 +280,7 @@ class XmlInputFactoryEventReader extends XmlParserCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() {
|
||||||
exists(SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig conf |
|
SafeXmlInputFactoryToXmlInputFactoryReaderFlow::flowToExpr(this.getQualifier())
|
||||||
conf.hasFlowToExpr(this.getQualifier())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,27 +375,24 @@ class SaxBuilderParse extends XmlParserCall {
|
|||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() {
|
||||||
exists(SafeSaxBuilderToSaxBuilderParseFlowConfig conf | conf.hasFlowToExpr(this.getQualifier()))
|
SafeSaxBuilderToSaxBuilderParseFlow::flowToExpr(this.getQualifier())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for SaxBuilderParse */
|
/** DEPRECATED: Alias for SaxBuilderParse */
|
||||||
deprecated class SAXBuilderParse = SaxBuilderParse;
|
deprecated class SAXBuilderParse = SaxBuilderParse;
|
||||||
|
|
||||||
private class SafeSaxBuilderToSaxBuilderParseFlowConfig extends DataFlow2::Configuration {
|
private module SafeSaxBuilderToSaxBuilderParseFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeSaxBuilderToSaxBuilderParseFlowConfig() {
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxBuilder }
|
||||||
this = "XmlParsers::SafeSAXBuilderToSAXBuilderParseFlowConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxBuilder }
|
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(SaxBuilderParse sax).getQualifier() }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
sink.asExpr() = any(SaxBuilderParse sax).getQualifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeSaxBuilderToSaxBuilderParseFlow =
|
||||||
|
DataFlow::Global<SafeSaxBuilderToSaxBuilderParseFlowConfig>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `ParserConfig` specific to `SAXBuilder`.
|
* A `ParserConfig` specific to `SAXBuilder`.
|
||||||
*/
|
*/
|
||||||
@@ -478,9 +463,7 @@ class SaxParserParse extends XmlParserCall {
|
|||||||
|
|
||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() { SafeSaxParserFlow::flowToExpr(this.getQualifier()) }
|
||||||
exists(SafeSaxParserFlowConfig sp | sp.hasFlowToExpr(this.getQualifier()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for SaxParserParse */
|
/** DEPRECATED: Alias for SaxParserParse */
|
||||||
@@ -536,14 +519,10 @@ class SafeSaxParserFactory extends VarAccess {
|
|||||||
/** DEPRECATED: Alias for SafeSaxParserFactory */
|
/** DEPRECATED: Alias for SafeSaxParserFactory */
|
||||||
deprecated class SafeSAXParserFactory = SafeSaxParserFactory;
|
deprecated class SafeSAXParserFactory = SafeSaxParserFactory;
|
||||||
|
|
||||||
private class SafeSaxParserFactoryToNewSaxParserFlowConfig extends DataFlow5::Configuration {
|
private module SafeSaxParserFactoryToNewSaxParserFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeSaxParserFactoryToNewSaxParserFlowConfig() {
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxParserFactory }
|
||||||
this = "XmlParsers::SafeSAXParserFactoryToNewSAXParserFlowConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxParserFactory }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(MethodAccess ma, Method m |
|
exists(MethodAccess ma, Method m |
|
||||||
sink.asExpr() = ma.getQualifier() and
|
sink.asExpr() = ma.getQualifier() and
|
||||||
ma.getMethod() = m and
|
ma.getMethod() = m and
|
||||||
@@ -552,31 +531,32 @@ private class SafeSaxParserFactoryToNewSaxParserFlowConfig extends DataFlow5::Co
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeSaxParserFlowConfig extends DataFlow4::Configuration {
|
private module SafeSaxParserFactoryToNewSaxParserFlow =
|
||||||
SafeSaxParserFlowConfig() { this = "XmlParsers::SafeSAXParserFlowConfig" }
|
DataFlow::Global<SafeSaxParserFactoryToNewSaxParserFlowConfig>;
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxParser }
|
private module SafeSaxParserFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxParser }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SaxParser
|
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SaxParser
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeSaxParserFlow = DataFlow::Global<SafeSaxParserFlowConfig>;
|
||||||
|
|
||||||
/** A `SaxParser` created from a safely configured `SaxParserFactory`. */
|
/** A `SaxParser` created from a safely configured `SaxParserFactory`. */
|
||||||
class SafeSaxParser extends MethodAccess {
|
class SafeSaxParser extends MethodAccess {
|
||||||
SafeSaxParser() {
|
SafeSaxParser() {
|
||||||
exists(SafeSaxParserFactoryToNewSaxParserFlowConfig sdf |
|
|
||||||
this.getMethod().getDeclaringType() instanceof SaxParserFactory and
|
this.getMethod().getDeclaringType() instanceof SaxParserFactory and
|
||||||
this.getMethod().hasName("newSAXParser") and
|
this.getMethod().hasName("newSAXParser") and
|
||||||
sdf.hasFlowToExpr(this.getQualifier())
|
SafeSaxParserFactoryToNewSaxParserFlow::flowToExpr(this.getQualifier())
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,9 +586,7 @@ class SaxReaderRead extends XmlParserCall {
|
|||||||
|
|
||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() { SafeSaxReaderFlow::flowToExpr(this.getQualifier()) }
|
||||||
exists(SafeSaxReaderFlowConfig sr | sr.hasFlowToExpr(this.getQualifier()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for SaxReaderRead */
|
/** DEPRECATED: Alias for SaxReaderRead */
|
||||||
@@ -628,20 +606,20 @@ class SaxReaderConfig extends ParserConfig {
|
|||||||
/** DEPRECATED: Alias for SaxReaderConfig */
|
/** DEPRECATED: Alias for SaxReaderConfig */
|
||||||
deprecated class SAXReaderConfig = SaxReaderConfig;
|
deprecated class SAXReaderConfig = SaxReaderConfig;
|
||||||
|
|
||||||
private class SafeSaxReaderFlowConfig extends DataFlow4::Configuration {
|
private module SafeSaxReaderFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeSaxReaderFlowConfig() { this = "XmlParsers::SafeSAXReaderFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxReader }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxReader }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
exists(MethodAccess ma |
|
exists(MethodAccess ma |
|
||||||
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SaxReader
|
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SaxReader
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeSaxReaderFlow = DataFlow::Global<SafeSaxReaderFlowConfig>;
|
||||||
|
|
||||||
/** A safely configured `SaxReader`. */
|
/** A safely configured `SaxReader`. */
|
||||||
class SafeSaxReader extends VarAccess {
|
class SafeSaxReader extends VarAccess {
|
||||||
SafeSaxReader() {
|
SafeSaxReader() {
|
||||||
@@ -715,18 +693,16 @@ class XmlReaderConfig extends ParserConfig {
|
|||||||
/** DEPRECATED: Alias for XmlReaderConfig */
|
/** DEPRECATED: Alias for XmlReaderConfig */
|
||||||
deprecated class XMLReaderConfig = XmlReaderConfig;
|
deprecated class XMLReaderConfig = XmlReaderConfig;
|
||||||
|
|
||||||
private class ExplicitlySafeXmlReaderFlowConfig extends DataFlow3::Configuration {
|
private module ExplicitlySafeXmlReaderFlowConfig implements DataFlow::ConfigSig {
|
||||||
ExplicitlySafeXmlReaderFlowConfig() { this = "XmlParsers::ExplicitlySafeXMLReaderFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ExplicitlySafeXmlReader }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SafeXmlReaderFlowSink }
|
||||||
src.asExpr() instanceof ExplicitlySafeXmlReader
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SafeXmlReaderFlowSink }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module ExplicitlySafeXmlReaderFlow = DataFlow::Global<ExplicitlySafeXmlReaderFlowConfig>;
|
||||||
|
|
||||||
/** An argument to a safe XML reader. */
|
/** An argument to a safe XML reader. */
|
||||||
class SafeXmlReaderFlowSink extends Expr {
|
class SafeXmlReaderFlowSink extends Expr {
|
||||||
SafeXmlReaderFlowSink() {
|
SafeXmlReaderFlowSink() {
|
||||||
@@ -774,40 +750,35 @@ class ExplicitlySafeXmlReader extends VarAccess {
|
|||||||
|
|
||||||
/** Holds if `SafeXmlReaderFlowSink` detects flow from this to `sink` */
|
/** Holds if `SafeXmlReaderFlowSink` detects flow from this to `sink` */
|
||||||
predicate flowsTo(SafeXmlReaderFlowSink sink) {
|
predicate flowsTo(SafeXmlReaderFlowSink sink) {
|
||||||
any(ExplicitlySafeXmlReaderFlowConfig conf)
|
ExplicitlySafeXmlReaderFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
|
||||||
.hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for ExplicitlySafeXmlReader */
|
/** DEPRECATED: Alias for ExplicitlySafeXmlReader */
|
||||||
deprecated class ExplicitlySafeXMLReader = ExplicitlySafeXmlReader;
|
deprecated class ExplicitlySafeXMLReader = ExplicitlySafeXmlReader;
|
||||||
|
|
||||||
private class CreatedSafeXmlReaderFlowConfig extends DataFlow3::Configuration {
|
private module CreatedSafeXmlReaderFlowConfig implements DataFlow::ConfigSig {
|
||||||
CreatedSafeXmlReaderFlowConfig() { this = "XmlParsers::CreatedSafeXMLReaderFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CreatedSafeXmlReader }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CreatedSafeXmlReader }
|
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SafeXmlReaderFlowSink }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SafeXmlReaderFlowSink }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module CreatedSafeXmlReaderFlow = DataFlow::Global<CreatedSafeXmlReaderFlowConfig>;
|
||||||
|
|
||||||
/** An `XmlReader` that is obtained from a safe source. */
|
/** An `XmlReader` that is obtained from a safe source. */
|
||||||
class CreatedSafeXmlReader extends Call {
|
class CreatedSafeXmlReader extends Call {
|
||||||
CreatedSafeXmlReader() {
|
CreatedSafeXmlReader() {
|
||||||
//Obtained from SAXParser
|
//Obtained from SAXParser
|
||||||
exists(SafeSaxParserFlowConfig safeParser |
|
|
||||||
this.(MethodAccess).getMethod().getDeclaringType() instanceof SaxParser and
|
this.(MethodAccess).getMethod().getDeclaringType() instanceof SaxParser and
|
||||||
this.(MethodAccess).getMethod().hasName("getXMLReader") and
|
this.(MethodAccess).getMethod().hasName("getXMLReader") and
|
||||||
safeParser.hasFlowToExpr(this.getQualifier())
|
SafeSaxParserFlow::flowToExpr(this.getQualifier())
|
||||||
)
|
|
||||||
or
|
or
|
||||||
//Obtained from SAXReader
|
//Obtained from SAXReader
|
||||||
exists(SafeSaxReaderFlowConfig safeReader |
|
|
||||||
this.(MethodAccess).getMethod().getDeclaringType() instanceof SaxReader and
|
this.(MethodAccess).getMethod().getDeclaringType() instanceof SaxReader and
|
||||||
this.(MethodAccess).getMethod().hasName("getXMLReader") and
|
this.(MethodAccess).getMethod().hasName("getXMLReader") and
|
||||||
safeReader.hasFlowToExpr(this.getQualifier())
|
SafeSaxReaderFlow::flowToExpr(this.getQualifier())
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(RefType secureReader, string package |
|
exists(RefType secureReader, string package |
|
||||||
this.(ClassInstanceExpr).getConstructedType() = secureReader and
|
this.(ClassInstanceExpr).getConstructedType() = secureReader and
|
||||||
@@ -818,8 +789,7 @@ class CreatedSafeXmlReader extends Call {
|
|||||||
|
|
||||||
/** Holds if `CreatedSafeXmlReaderFlowConfig` detects flow from this to `sink` */
|
/** Holds if `CreatedSafeXmlReaderFlowConfig` detects flow from this to `sink` */
|
||||||
predicate flowsTo(SafeXmlReaderFlowSink sink) {
|
predicate flowsTo(SafeXmlReaderFlowSink sink) {
|
||||||
any(CreatedSafeXmlReaderFlowConfig conf)
|
CreatedSafeXmlReaderFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
|
||||||
.hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,26 +945,23 @@ class TransformerTransform extends XmlParserCall {
|
|||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() {
|
||||||
exists(SafeTransformerToTransformerTransformFlowConfig st |
|
SafeTransformerToTransformerTransformFlow::flowToExpr(this.getQualifier())
|
||||||
st.hasFlowToExpr(this.getQualifier())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeTransformerToTransformerTransformFlowConfig extends DataFlow2::Configuration {
|
private module SafeTransformerToTransformerTransformFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeTransformerToTransformerTransformFlowConfig() {
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeTransformer }
|
||||||
this = "XmlParsers::SafeTransformerToTransformerTransformFlowConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeTransformer }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
sink.asExpr() = any(TransformerTransform tt).getQualifier()
|
sink.asExpr() = any(TransformerTransform tt).getQualifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeTransformerToTransformerTransformFlow =
|
||||||
|
DataFlow::Global<SafeTransformerToTransformerTransformFlowConfig>;
|
||||||
|
|
||||||
/** A call to `Transformer.newTransformer` with source. */
|
/** A call to `Transformer.newTransformer` with source. */
|
||||||
class TransformerFactorySource extends XmlParserCall {
|
class TransformerFactorySource extends XmlParserCall {
|
||||||
TransformerFactorySource() {
|
TransformerFactorySource() {
|
||||||
@@ -1007,9 +974,7 @@ class TransformerFactorySource extends XmlParserCall {
|
|||||||
|
|
||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() { SafeTransformerFactoryFlow::flowToExpr(this.getQualifier()) }
|
||||||
exists(SafeTransformerFactoryFlowConfig stf | stf.hasFlowToExpr(this.getQualifier()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A `ParserConfig` specific to `TransformerFactory`. */
|
/** A `ParserConfig` specific to `TransformerFactory`. */
|
||||||
@@ -1024,10 +989,12 @@ class TransformerFactoryConfig extends TransformerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `SafeTransformerFactoryFlow` instead.
|
||||||
|
*
|
||||||
* A dataflow configuration that identifies `TransformerFactory` and `SAXTransformerFactory`
|
* A dataflow configuration that identifies `TransformerFactory` and `SAXTransformerFactory`
|
||||||
* instances that have been safely configured.
|
* instances that have been safely configured.
|
||||||
*/
|
*/
|
||||||
class SafeTransformerFactoryFlowConfig extends DataFlow3::Configuration {
|
deprecated class SafeTransformerFactoryFlowConfig extends DataFlow3::Configuration {
|
||||||
SafeTransformerFactoryFlowConfig() { this = "XmlParsers::SafeTransformerFactoryFlowConfig" }
|
SafeTransformerFactoryFlowConfig() { this = "XmlParsers::SafeTransformerFactoryFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeTransformerFactory }
|
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeTransformerFactory }
|
||||||
@@ -1042,6 +1009,29 @@ class SafeTransformerFactoryFlowConfig extends DataFlow3::Configuration {
|
|||||||
override int fieldFlowBranchLimit() { result = 0 }
|
override int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dataflow configuration that identifies `TransformerFactory` and `SAXTransformerFactory`
|
||||||
|
* instances that have been safely configured.
|
||||||
|
*/
|
||||||
|
module SafeTransformerFactoryFlowConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeTransformerFactory }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(MethodAccess ma |
|
||||||
|
sink.asExpr() = ma.getQualifier() and
|
||||||
|
ma.getMethod().getDeclaringType() instanceof TransformerFactory
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies `TransformerFactory` and `SAXTransformerFactory`
|
||||||
|
* instances that have been safely configured.
|
||||||
|
*/
|
||||||
|
module SafeTransformerFactoryFlow = DataFlow::Global<SafeTransformerFactoryFlowConfig>;
|
||||||
|
|
||||||
/** A safely configured `TransformerFactory`. */
|
/** A safely configured `TransformerFactory`. */
|
||||||
class SafeTransformerFactory extends VarAccess {
|
class SafeTransformerFactory extends VarAccess {
|
||||||
SafeTransformerFactory() {
|
SafeTransformerFactory() {
|
||||||
@@ -1059,11 +1049,11 @@ class SafeTransformerFactory extends VarAccess {
|
|||||||
/** A `Transformer` created from a safely configured `TransformerFactory`. */
|
/** A `Transformer` created from a safely configured `TransformerFactory`. */
|
||||||
class SafeTransformer extends MethodAccess {
|
class SafeTransformer extends MethodAccess {
|
||||||
SafeTransformer() {
|
SafeTransformer() {
|
||||||
exists(SafeTransformerFactoryFlowConfig stf, Method m |
|
exists(Method m |
|
||||||
this.getMethod() = m and
|
this.getMethod() = m and
|
||||||
m.getDeclaringType() instanceof TransformerFactory and
|
m.getDeclaringType() instanceof TransformerFactory and
|
||||||
m.hasName("newTransformer") and
|
m.hasName("newTransformer") and
|
||||||
stf.hasFlowToExpr(this.getQualifier())
|
SafeTransformerFactoryFlow::flowToExpr(this.getQualifier())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,9 +1075,7 @@ class SaxTransformerFactoryNewXmlFilter extends XmlParserCall {
|
|||||||
|
|
||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() { SafeTransformerFactoryFlow::flowToExpr(this.getQualifier()) }
|
||||||
exists(SafeTransformerFactoryFlowConfig stf | stf.hasFlowToExpr(this.getQualifier()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for SaxTransformerFactoryNewXmlFilter */
|
/** DEPRECATED: Alias for SaxTransformerFactoryNewXmlFilter */
|
||||||
@@ -1123,26 +1111,23 @@ class SchemaFactoryNewSchema extends XmlParserCall {
|
|||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() {
|
||||||
exists(SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig ssf |
|
SafeSchemaFactoryToSchemaFactoryNewSchemaFlow::flowToExpr(this.getQualifier())
|
||||||
ssf.hasFlowToExpr(this.getQualifier())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig extends DataFlow2::Configuration {
|
private module SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig() {
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSchemaFactory }
|
||||||
this = "XmlParsers::SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig"
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSchemaFactory }
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
|
||||||
sink.asExpr() = any(SchemaFactoryNewSchema sfns).getQualifier()
|
sink.asExpr() = any(SchemaFactoryNewSchema sfns).getQualifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeSchemaFactoryToSchemaFactoryNewSchemaFlow =
|
||||||
|
DataFlow::Global<SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig>;
|
||||||
|
|
||||||
/** A safely configured `SchemaFactory`. */
|
/** A safely configured `SchemaFactory`. */
|
||||||
class SafeSchemaFactory extends VarAccess {
|
class SafeSchemaFactory extends VarAccess {
|
||||||
SafeSchemaFactory() {
|
SafeSchemaFactory() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** Provides default definitions to be used in XXE queries. */
|
/** Provides default definitions to be used in XXE queries. */
|
||||||
|
|
||||||
import java
|
import java
|
||||||
private import semmle.code.java.dataflow.TaintTracking2
|
private import semmle.code.java.dataflow.TaintTracking
|
||||||
private import semmle.code.java.security.XmlParsers
|
private import semmle.code.java.security.XmlParsers
|
||||||
import semmle.code.java.security.Xxe
|
import semmle.code.java.security.Xxe
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import semmle.code.java.security.Xxe
|
|||||||
*/
|
*/
|
||||||
private class DefaultXxeSink extends XxeSink {
|
private class DefaultXxeSink extends XxeSink {
|
||||||
DefaultXxeSink() {
|
DefaultXxeSink() {
|
||||||
not exists(SafeSaxSourceFlowConfig safeSource | safeSource.hasFlowTo(this)) and
|
not SafeSaxSourceFlow::flowTo(this) and
|
||||||
exists(XmlParserCall parse |
|
exists(XmlParserCall parse |
|
||||||
parse.getSink() = this.asExpr() and
|
parse.getSink() = this.asExpr() and
|
||||||
not parse.isSafe()
|
not parse.isSafe()
|
||||||
@@ -22,14 +22,12 @@ private class DefaultXxeSink extends XxeSink {
|
|||||||
/**
|
/**
|
||||||
* A taint-tracking configuration for safe XML readers used to parse XML documents.
|
* A taint-tracking configuration for safe XML readers used to parse XML documents.
|
||||||
*/
|
*/
|
||||||
private class SafeSaxSourceFlowConfig extends TaintTracking2::Configuration {
|
private module SafeSaxSourceFlowConfig implements DataFlow::ConfigSig {
|
||||||
SafeSaxSourceFlowConfig() { this = "SafeSaxSourceFlowConfig" }
|
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxSource }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxSource }
|
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(XmlParserCall parse).getSink() }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
int fieldFlowBranchLimit() { result = 0 }
|
||||||
sink.asExpr() = any(XmlParserCall parse).getSink()
|
|
||||||
}
|
|
||||||
|
|
||||||
override int fieldFlowBranchLimit() { result = 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private module SafeSaxSourceFlow = TaintTracking::Global<SafeSaxSourceFlowConfig>;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ deprecated predicate hasPolynomialReDoSResult(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A configuration for Polynomial ReDoS queries. */
|
/** A configuration for Polynomial ReDoS queries. */
|
||||||
private module PolynomialRedosConfig implements DataFlow::ConfigSig {
|
module PolynomialRedosConfig implements DataFlow::ConfigSig {
|
||||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import java
|
|||||||
import semmle.code.java.dataflow.FlowSources
|
import semmle.code.java.dataflow.FlowSources
|
||||||
import semmle.code.java.dataflow.TaintTracking
|
import semmle.code.java.dataflow.TaintTracking
|
||||||
import semmle.code.java.security.ExternalAPIs
|
import semmle.code.java.security.ExternalAPIs
|
||||||
import DataFlow::PathGraph
|
import UntrustedDataToExternalApiFlow::PathGraph
|
||||||
|
|
||||||
from UntrustedDataToExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
from UntrustedDataToExternalApiFlow::PathNode source, UntrustedDataToExternalApiFlow::PathNode sink
|
||||||
where config.hasFlowPath(source, sink)
|
where UntrustedDataToExternalApiFlow::flowPath(source, sink)
|
||||||
select sink, source, sink,
|
select sink, source, sink,
|
||||||
"Call to " + sink.getNode().(ExternalApiDataNode).getMethodDescription() +
|
"Call to " + sink.getNode().(ExternalApiDataNode).getMethodDescription() +
|
||||||
" with untrusted data from $@.", source, source.toString()
|
" with untrusted data from $@.", source, source.toString()
|
||||||
|
|||||||
@@ -11,10 +11,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.java.security.PartialPathTraversalQuery
|
import semmle.code.java.security.PartialPathTraversalQuery
|
||||||
import DataFlow::PathGraph
|
import PartialPathTraversalFromRemoteFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink
|
from
|
||||||
where any(PartialPathTraversalFromRemoteConfig config).hasFlowPath(source, sink)
|
PartialPathTraversalFromRemoteFlow::PathNode source,
|
||||||
|
PartialPathTraversalFromRemoteFlow::PathNode sink
|
||||||
|
where PartialPathTraversalFromRemoteFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@.",
|
"Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@.",
|
||||||
source, "user-supplied data"
|
source, "user-supplied data"
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.security.StaticInitializationVectorQuery
|
import semmle.code.java.security.StaticInitializationVectorQuery
|
||||||
import DataFlow::PathGraph
|
import StaticInitializationVectorFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, StaticInitializationVectorConfig conf
|
from StaticInitializationVectorFlow::PathNode source, StaticInitializationVectorFlow::PathNode sink
|
||||||
where conf.hasFlowPath(source, sink)
|
where StaticInitializationVectorFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "A $@ should not be used for encryption.", source.getNode(),
|
select sink.getNode(), source, sink, "A $@ should not be used for encryption.", source.getNode(),
|
||||||
"static initialization vector"
|
"static initialization vector"
|
||||||
|
|||||||
@@ -18,7 +18,5 @@ import semmle.code.java.security.UnsafeCertTrustQuery
|
|||||||
from Expr unsafeTrust
|
from Expr unsafeTrust
|
||||||
where
|
where
|
||||||
unsafeTrust instanceof RabbitMQEnableHostnameVerificationNotSet or
|
unsafeTrust instanceof RabbitMQEnableHostnameVerificationNotSet or
|
||||||
exists(SslEndpointIdentificationFlowConfig config |
|
SslEndpointIdentificationFlow::flowTo(DataFlow::exprNode(unsafeTrust))
|
||||||
config.hasFlowTo(DataFlow::exprNode(unsafeTrust))
|
|
||||||
)
|
|
||||||
select unsafeTrust, "Unsafe configuration of trusted certificates."
|
select unsafeTrust, "Unsafe configuration of trusted certificates."
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.security.InsecureTrustManagerQuery
|
import semmle.code.java.security.InsecureTrustManagerQuery
|
||||||
import DataFlow::PathGraph
|
import InsecureTrustManagerFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink
|
from InsecureTrustManagerFlow::PathNode source, InsecureTrustManagerFlow::PathNode sink
|
||||||
where any(InsecureTrustManagerConfiguration cfg).hasFlowPath(source, sink)
|
where InsecureTrustManagerFlow::flowPath(source, sink)
|
||||||
select sink, source, sink, "This uses $@, which is defined in $@ and trusts any certificate.",
|
select sink, source, sink, "This uses $@, which is defined in $@ and trusts any certificate.",
|
||||||
source, "TrustManager",
|
source, "TrustManager",
|
||||||
source.getNode().asExpr().(ClassInstanceExpr).getConstructedType() as type, type.nestedName()
|
source.getNode().asExpr().(ClassInstanceExpr).getConstructedType() as type, type.nestedName()
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.security.HttpsUrlsQuery
|
import semmle.code.java.security.HttpsUrlsQuery
|
||||||
import DataFlow::PathGraph
|
import HttpStringToUrlOpenMethodFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink
|
from HttpStringToUrlOpenMethodFlow::PathNode source, HttpStringToUrlOpenMethodFlow::PathNode sink
|
||||||
where any(HttpStringToUrlOpenMethodFlowConfig c).hasFlowPath(source, sink)
|
where HttpStringToUrlOpenMethodFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "URL may have been constructed with HTTP protocol, using $@.",
|
select sink.getNode(), source, sink, "URL may have been constructed with HTTP protocol, using $@.",
|
||||||
source.getNode(), "this HTTP URL"
|
source.getNode(), "this HTTP URL"
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.security.InsufficientKeySizeQuery
|
import semmle.code.java.security.InsufficientKeySizeQuery
|
||||||
import DataFlow::PathGraph
|
import KeySizeFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, KeySizeConfiguration cfg
|
from KeySizeFlow::PathNode source, KeySizeFlow::PathNode sink
|
||||||
where cfg.hasFlowPath(source, sink)
|
where KeySizeFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"This $@ is less than the recommended key size of " + source.getState() + " bits.",
|
"This $@ is less than the recommended key size of " + source.getState() + " bits.",
|
||||||
source.getNode(), "key size"
|
source.getNode(), "key size"
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.security.MissingJWTSignatureCheckQuery
|
import semmle.code.java.security.MissingJWTSignatureCheckQuery
|
||||||
import DataFlow::PathGraph
|
import MissingJwtSignatureCheckFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, MissingJwtSignatureCheckConf conf
|
from MissingJwtSignatureCheckFlow::PathNode source, MissingJwtSignatureCheckFlow::PathNode sink
|
||||||
where conf.hasFlowPath(source, sink)
|
where MissingJwtSignatureCheckFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "This parses a $@, but the signature is not verified.",
|
select sink.getNode(), source, sink, "This parses a $@, but the signature is not verified.",
|
||||||
source.getNode(), "JWT signing key"
|
source.getNode(), "JWT signing key"
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.security.UnsafeDeserializationQuery
|
import semmle.code.java.security.UnsafeDeserializationQuery
|
||||||
import DataFlow::PathGraph
|
import UnsafeDeserializationFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeDeserializationConfig conf
|
from UnsafeDeserializationFlow::PathNode source, UnsafeDeserializationFlow::PathNode sink
|
||||||
where conf.hasFlowPath(source, sink)
|
where UnsafeDeserializationFlow::flowPath(source, sink)
|
||||||
select sink.getNode().(UnsafeDeserializationSink).getMethodAccess(), source, sink,
|
select sink.getNode().(UnsafeDeserializationSink).getMethodAccess(), source, sink,
|
||||||
"Unsafe deserialization depends on a $@.", source.getNode(), "user-provided value"
|
"Unsafe deserialization depends on a $@.", source.getNode(), "user-provided value"
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.security.InsecureBasicAuthQuery
|
import semmle.code.java.security.InsecureBasicAuthQuery
|
||||||
import DataFlow::PathGraph
|
import InsecureBasicAuthFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, BasicAuthFlowConfig config
|
from InsecureBasicAuthFlow::PathNode source, InsecureBasicAuthFlow::PathNode sink
|
||||||
where config.hasFlowPath(source, sink)
|
where InsecureBasicAuthFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink, "Insecure basic authentication from a $@.", source.getNode(),
|
select sink.getNode(), source, sink, "Insecure basic authentication from a $@.", source.getNode(),
|
||||||
"HTTP URL"
|
"HTTP URL"
|
||||||
|
|||||||
@@ -11,10 +11,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.java.security.HardcodedCredentialsApiCallQuery
|
import semmle.code.java.security.HardcodedCredentialsApiCallQuery
|
||||||
import DataFlow::PathGraph
|
import HardcodedCredentialApiCallFlow::PathGraph
|
||||||
|
|
||||||
from
|
from HardcodedCredentialApiCallFlow::PathNode source, HardcodedCredentialApiCallFlow::PathNode sink
|
||||||
DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedCredentialApiCallConfiguration conf
|
where HardcodedCredentialApiCallFlow::flowPath(source, sink)
|
||||||
where conf.hasFlowPath(source, sink)
|
|
||||||
select source.getNode(), source, sink, "Hard-coded value flows to $@.", sink.getNode(),
|
select source.getNode(), source, sink, "Hard-coded value flows to $@.", sink.getNode(),
|
||||||
"sensitive API call"
|
"sensitive API call"
|
||||||
|
|||||||
@@ -15,15 +15,15 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.security.ConditionalBypassQuery
|
import semmle.code.java.security.ConditionalBypassQuery
|
||||||
import DataFlow::PathGraph
|
import ConditionalBypassFlow::PathGraph
|
||||||
|
|
||||||
from
|
from
|
||||||
DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess m, Expr e,
|
ConditionalBypassFlow::PathNode source, ConditionalBypassFlow::PathNode sink, MethodAccess m,
|
||||||
ConditionalBypassFlowConfig conf
|
Expr e
|
||||||
where
|
where
|
||||||
conditionControlsMethod(m, e) and
|
conditionControlsMethod(m, e) and
|
||||||
sink.getNode().asExpr() = e and
|
sink.getNode().asExpr() = e and
|
||||||
conf.hasFlowPath(source, sink)
|
ConditionalBypassFlow::flowPath(source, sink)
|
||||||
select m, source, sink,
|
select m, source, sink,
|
||||||
"Sensitive method may not be executed depending on a $@, which flows from $@.", e,
|
"Sensitive method may not be executed depending on a $@, which flows from $@.", e,
|
||||||
"this condition", source.getNode(), "user-controlled value"
|
"this condition", source.getNode(), "user-controlled value"
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.security.ImplicitPendingIntentsQuery
|
import semmle.code.java.security.ImplicitPendingIntentsQuery
|
||||||
import DataFlow::PathGraph
|
import ImplicitPendingIntentStartFlow::PathGraph
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink
|
from ImplicitPendingIntentStartFlow::PathNode source, ImplicitPendingIntentStartFlow::PathNode sink
|
||||||
where any(ImplicitPendingIntentStartConf conf).hasFlowPath(source, sink)
|
where ImplicitPendingIntentStartFlow::flowPath(source, sink)
|
||||||
select sink.getNode(), source, sink,
|
select sink.getNode(), source, sink,
|
||||||
"$@ and sent to an unspecified third party through a PendingIntent.", source.getNode(),
|
"$@ and sent to an unspecified third party through a PendingIntent.", source.getNode(),
|
||||||
"An implicit Intent is created"
|
"An implicit Intent is created"
|
||||||
|
|||||||
@@ -232,9 +232,7 @@ class SaxTransformerFactoryNewTransformerHandler extends XmlParserCall {
|
|||||||
|
|
||||||
override Expr getSink() { result = this.getArgument(0) }
|
override Expr getSink() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override predicate isSafe() {
|
override predicate isSafe() { SafeTransformerFactoryFlow::flowToExpr(this.getQualifier()) }
|
||||||
exists(SafeTransformerFactoryFlowConfig stf | stf.hasFlowToExpr(this.getQualifier()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED: Alias for SaxTransformerFactoryNewTransformerHandler */
|
/** DEPRECATED: Alias for SaxTransformerFactoryNewTransformerHandler */
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
import java
|
import java
|
||||||
import TestUtilities.InlineFlowTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
import semmle.code.java.security.PartialPathTraversalQuery
|
import semmle.code.java.security.PartialPathTraversalQuery
|
||||||
|
|
||||||
class EnableLegacy extends EnableLegacyConfiguration {
|
|
||||||
EnableLegacy() { exists(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestRemoteSource extends RemoteFlowSource {
|
class TestRemoteSource extends RemoteFlowSource {
|
||||||
TestRemoteSource() { this.asParameter().hasName(["dir", "path"]) }
|
TestRemoteSource() { this.asParameter().hasName(["dir", "path"]) }
|
||||||
|
|
||||||
override string getSourceType() { result = "TestSource" }
|
override string getSourceType() { result = "TestSource" }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Test extends InlineFlowTest {
|
class Test extends InlineExpectationsTest {
|
||||||
override DataFlow::Configuration getValueFlowConfig() { none() }
|
Test() { this = "PartialPathTraversalFromRemoteTest" }
|
||||||
|
|
||||||
override TaintTracking::Configuration getTaintFlowConfig() {
|
override string getARelevantTag() { result = "hasTaintFlow" }
|
||||||
result instanceof PartialPathTraversalFromRemoteConfig
|
|
||||||
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
tag = "hasTaintFlow" and
|
||||||
|
exists(DataFlow::Node sink | PartialPathTraversalFromRemoteFlow::flowTo(sink) |
|
||||||
|
sink.getLocation() = location and
|
||||||
|
element = sink.toString() and
|
||||||
|
value = ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class StaticInitializationVectorTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "staticInitializationVector" and
|
tag = "staticInitializationVector" and
|
||||||
exists(DataFlow::Node sink, StaticInitializationVectorConfig conf | conf.hasFlowTo(sink) |
|
exists(DataFlow::Node sink | StaticInitializationVectorFlow::flowTo(sink) |
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
element = sink.toString() and
|
element = sink.toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ class UnsafeCertTrustTest extends InlineExpectationsTest {
|
|||||||
exists(Expr unsafeTrust |
|
exists(Expr unsafeTrust |
|
||||||
unsafeTrust instanceof RabbitMQEnableHostnameVerificationNotSet
|
unsafeTrust instanceof RabbitMQEnableHostnameVerificationNotSet
|
||||||
or
|
or
|
||||||
exists(SslEndpointIdentificationFlowConfig config |
|
SslEndpointIdentificationFlow::flowTo(DataFlow::exprNode(unsafeTrust))
|
||||||
config.hasFlowTo(DataFlow::exprNode(unsafeTrust))
|
|
||||||
)
|
|
||||||
|
|
|
|
||||||
unsafeTrust.getLocation() = location and
|
unsafeTrust.getLocation() = location and
|
||||||
element = unsafeTrust.toString() and
|
element = unsafeTrust.toString() and
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.security.InsecureTrustManagerQuery
|
import semmle.code.java.security.InsecureTrustManagerQuery
|
||||||
import TestUtilities.InlineFlowTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
class EnableLegacy extends EnableLegacyConfiguration {
|
class InsecureTrustManagerTest extends InlineExpectationsTest {
|
||||||
EnableLegacy() { exists(this) }
|
InsecureTrustManagerTest() { this = "InsecureTrustManagerTest" }
|
||||||
}
|
|
||||||
|
|
||||||
class InsecureTrustManagerTest extends InlineFlowTest {
|
override string getARelevantTag() { result = "hasValueFlow" }
|
||||||
override DataFlow::Configuration getValueFlowConfig() {
|
|
||||||
result = any(InsecureTrustManagerConfiguration c)
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
|
tag = "hasValueFlow" and
|
||||||
|
exists(DataFlow::Node sink | InsecureTrustManagerFlow::flowTo(sink) |
|
||||||
|
sink.getLocation() = location and
|
||||||
|
element = sink.toString() and
|
||||||
|
value = ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class InsufficientKeySizeTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "hasInsufficientKeySize" and
|
tag = "hasInsufficientKeySize" and
|
||||||
exists(DataFlow::PathNode sink | exists(KeySizeConfiguration cfg | cfg.hasFlowPath(_, sink)) |
|
exists(KeySizeFlow::PathNode sink | KeySizeFlow::flowPath(_, sink) |
|
||||||
sink.getNode().getLocation() = location and
|
sink.getNode().getLocation() = location and
|
||||||
element = sink.getNode().toString() and
|
element = sink.getNode().toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class HasMissingJwtSignatureCheckTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "hasMissingJwtSignatureCheck" and
|
tag = "hasMissingJwtSignatureCheck" and
|
||||||
exists(DataFlow::Node sink, MissingJwtSignatureCheckConf conf | conf.hasFlowTo(sink) |
|
exists(DataFlow::Node sink | MissingJwtSignatureCheckFlow::flowTo(sink) |
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
element = sink.toString() and
|
element = sink.toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class UnsafeDeserializationTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "unsafeDeserialization" and
|
tag = "unsafeDeserialization" and
|
||||||
exists(DataFlow::Node sink, UnsafeDeserializationConfig conf | conf.hasFlowTo(sink) |
|
exists(DataFlow::Node sink | UnsafeDeserializationFlow::flowTo(sink) |
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
element = sink.toString() and
|
element = sink.toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class HasInsecureBasicAuthTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "hasInsecureBasicAuth" and
|
tag = "hasInsecureBasicAuth" and
|
||||||
exists(DataFlow::Node sink, BasicAuthFlowConfig conf | conf.hasFlowTo(sink) |
|
exists(DataFlow::Node sink | InsecureBasicAuthFlow::flowTo(sink) |
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
element = sink.toString() and
|
element = sink.toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ class HardcodedCredentialsApiCallTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "HardcodedCredentialsApiCall" and
|
tag = "HardcodedCredentialsApiCall" and
|
||||||
exists(DataFlow::Node sink, HardcodedCredentialApiCallConfiguration conf |
|
exists(DataFlow::Node sink | HardcodedCredentialApiCallFlow::flowTo(sink) |
|
||||||
conf.hasFlow(_, sink)
|
|
||||||
|
|
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
element = sink.toString() and
|
element = sink.toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class ConditionalBypassTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "hasConditionalBypassTest" and
|
tag = "hasConditionalBypassTest" and
|
||||||
exists(DataFlow::Node sink, ConditionalBypassFlowConfig conf | conf.hasFlowTo(sink) |
|
exists(DataFlow::Node sink | ConditionalBypassFlow::flowTo(sink) |
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
element = sink.toString() and
|
element = sink.toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class ImplicitPendingIntentsTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
tag = "hasImplicitPendingIntent" and
|
tag = "hasImplicitPendingIntent" and
|
||||||
exists(DataFlow::Node sink | any(ImplicitPendingIntentStartConf c).hasFlowTo(sink) |
|
exists(DataFlow::Node sink | ImplicitPendingIntentStartFlow::flowTo(sink) |
|
||||||
sink.getLocation() = location and
|
sink.getLocation() = location and
|
||||||
element = sink.toString() and
|
element = sink.toString() and
|
||||||
value = ""
|
value = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user