mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Merge branch 'main' into swift/case-let-dataflow
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed some accidental predicate visibility in the backwards-compatible wrapper for data flow configurations. In particular `DataFlow::hasFlowPath`, `DataFlow::hasFlow`, `DataFlow::hasFlowTo`, and `DataFlow::hasFlowToExpr` were accidentally exposed in a single version.
|
||||
@@ -1039,6 +1039,29 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
or
|
||||
b = bRight and origdelta = odRight and reason = rRight and bLeft instanceof SemZeroBound
|
||||
)
|
||||
or
|
||||
exists(
|
||||
SemRemExpr rem, SemZeroBound b1, SemZeroBound b2, D::Delta d_max, D::Delta d1, D::Delta d2,
|
||||
boolean fbe1, boolean fbe2, D::Delta od1, D::Delta od2, SemReason r1, SemReason r2
|
||||
|
|
||||
rem = e and
|
||||
not (upper = true and semPositive(rem.getRightOperand())) and
|
||||
not (upper = true and semPositive(rem.getLeftOperand())) and
|
||||
boundedRemExpr(rem, b1, true, d1, fbe1, od1, r1) and
|
||||
boundedRemExpr(rem, b2, false, d2, fbe2, od2, r2) and
|
||||
(
|
||||
if D::toFloat(d1).abs() > D::toFloat(d2).abs()
|
||||
then (
|
||||
b = b1 and d_max = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
) else (
|
||||
b = b2 and d_max = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
)
|
||||
)
|
||||
|
|
||||
upper = true and delta = D::fromFloat(D::toFloat(d_max).abs() - 1)
|
||||
or
|
||||
upper = false and delta = D::fromFloat(-D::toFloat(d_max).abs() + 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1065,4 +1088,11 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
bounded(add.getRightOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate boundedRemExpr(
|
||||
SemRemExpr rem, SemZeroBound b, boolean upper, D::Delta delta, boolean fromBackEdge,
|
||||
D::Delta origdelta, SemReason reason
|
||||
) {
|
||||
bounded(rem.getRightOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -18,20 +18,20 @@ int test2(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
count = (count+1) % 10;
|
||||
range(count); // $ range=<=9
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
}
|
||||
range(count); // $ range=<=9
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
}
|
||||
|
||||
int test3(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
range(count++); // $ range=<=9
|
||||
range(count++); // $ range=>=-9 range=<=9
|
||||
count = count % 10;
|
||||
range(count); // $ range=<=9
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
}
|
||||
range(count); // $ range=<=9
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -960,7 +960,22 @@ void guard_bound_out_of_range(void) {
|
||||
|
||||
void test_mod(int s) {
|
||||
int s2 = s % 5;
|
||||
range(s2); // $ range=<=4 // -4 .. 4
|
||||
range(s2); // $ range=>=-4 range=<=4
|
||||
}
|
||||
|
||||
void test_mod_neg(int s) {
|
||||
int s2 = s % -5;
|
||||
range(s2); // $ range=>=-4 range=<=4
|
||||
}
|
||||
|
||||
void test_mod_ternary(int s, bool b) {
|
||||
int s2 = s % (b ? 5 : 500);
|
||||
range(s2); // $ range=>=-499 range=<=499
|
||||
}
|
||||
|
||||
void test_mod_ternary2(int s, bool b1, bool b2) {
|
||||
int s2 = s % (b1 ? (b2 ? 5 : -5000) : -500000);
|
||||
range(s2); // $ range=>=-499999 range=<=499999
|
||||
}
|
||||
|
||||
void exit(int);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed some accidental predicate visibility in the backwards-compatible wrapper for data flow configurations. In particular `DataFlow::hasFlowPath`, `DataFlow::hasFlow`, `DataFlow::hasFlowTo`, and `DataFlow::hasFlowToExpr` were accidentally exposed in a single version.
|
||||
@@ -11,6 +11,13 @@ class WebConfigXml extends XmlFile {
|
||||
WebConfigXml() { this.getName().matches("%Web.config") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Web.config` transformation file.
|
||||
*/
|
||||
class WebConfigReleaseTransformXml extends XmlFile {
|
||||
WebConfigReleaseTransformXml() { this.getName().matches("%Web.Release.config") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for WebConfigXml */
|
||||
deprecated class WebConfigXML = WebConfigXml;
|
||||
|
||||
@@ -19,6 +26,11 @@ class ConfigurationXmlElement extends XmlElement {
|
||||
ConfigurationXmlElement() { this.getName().toLowerCase() = "configuration" }
|
||||
}
|
||||
|
||||
/** A `<compilation>` tag in an ASP.NET configuration file. */
|
||||
class CompilationXmlElement extends XmlElement {
|
||||
CompilationXmlElement() { this.getName().toLowerCase() = "compilation" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ConfigurationXmlElement */
|
||||
deprecated class ConfigurationXMLElement = ConfigurationXmlElement;
|
||||
|
||||
@@ -149,3 +161,15 @@ class HttpCookiesElement extends XmlElement {
|
||||
/** DEPRECATED: Alias for isRequireSsl */
|
||||
deprecated predicate isRequireSSL() { this.isRequireSsl() }
|
||||
}
|
||||
|
||||
/** A `Transform` attribute in a Web.config transformation file. */
|
||||
class TransformXmlAttribute extends XmlAttribute {
|
||||
TransformXmlAttribute() { this.getName().toLowerCase() = "transform" }
|
||||
|
||||
/**
|
||||
* Gets the list of attribute removals in `Transform=RemoveAttributes(list)`.
|
||||
*/
|
||||
string getRemoveAttributes() {
|
||||
result = this.getValue().regexpCapture("RemoveAttributes\\((.*)\\)", 1).splitAt(",")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -19,6 +19,17 @@ import semmle.code.asp.WebConfig
|
||||
|
||||
from SystemWebXmlElement web, XmlAttribute debugAttribute
|
||||
where
|
||||
debugAttribute = web.getAChild("compilation").getAttribute("debug") and
|
||||
not debugAttribute.getValue().toLowerCase() = "false"
|
||||
exists(CompilationXmlElement compilation | compilation.getParent() = web |
|
||||
debugAttribute = compilation.getAttribute("debug") and
|
||||
not debugAttribute.getValue().toLowerCase() = "false"
|
||||
) and
|
||||
not exists(
|
||||
TransformXmlAttribute attribute, CompilationXmlElement compilation,
|
||||
WebConfigReleaseTransformXml file
|
||||
|
|
||||
compilation = attribute.getElement() and
|
||||
file = compilation.getFile() and
|
||||
attribute.getRemoveAttributes() = "debug" and
|
||||
file.getParentContainer() = web.getFile().getParentContainer()
|
||||
)
|
||||
select debugAttribute, "The 'debug' flag is set for an ASP.NET configuration file."
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `cs/web/debug-binary` now disregards the `debug` attribute in case there is a transformation that removes it.
|
||||
@@ -1 +1,2 @@
|
||||
| bad/Web.config:4:5:7:7 | debug=true | The 'debug' flag is set for an ASP.NET configuration file. |
|
||||
| bad1/Web.config:4:5:7:7 | debug=true | The 'debug' flag is set for an ASP.NET configuration file. |
|
||||
| bad2/Web.config:4:5:7:7 | debug=true | The 'debug' flag is set for an ASP.NET configuration file. |
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<system.web>
|
||||
<compilation xdt:Transform="RemoveAttributes(debug)" />
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<system.web>
|
||||
<compilation
|
||||
defaultLanguage="c#"
|
||||
debug="true"
|
||||
/>
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<system.web>
|
||||
<compilation xdt:Transform="RemoveAttributes(debug)" />
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<system.web>
|
||||
<compilation
|
||||
defaultLanguage="c#"
|
||||
debug="true"
|
||||
/>
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -45,4 +45,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
- :doc:`Working with source locations <working-with-source-locations>`: You can use the location of entities within Java code to look for potential errors. Locations allow you to deduce the presence, or absence, of white space which, in some cases, may indicate a problem.
|
||||
|
||||
- :doc:`Abstract syntax tree classes for working with Java programs <abstract-syntax-tree-classes-for-working-with-java-programs>`: CodeQL has a large selection of classes for representing the abstract syntax tree of Java programs.
|
||||
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
.. _customizing-library-models-for-java:
|
||||
|
||||
:orphan:
|
||||
:nosearch:
|
||||
|
||||
Customizing Library Models for Java
|
||||
===================================
|
||||
|
||||
.. include:: ../reusables/beta-note-customizing-library-models.rst
|
||||
|
||||
The Java analysis can be customized by adding library models (summaries, sinks and sources) in data extension files.
|
||||
A model is a definition of a behavior of a library element, such as a method, that is used to improve the data flow analysis precision by identifying more results.
|
||||
Most of the security related queries are taint tracking queries that try to find paths from a source of untrusted input to a sink that represents a vulnerability. Sources are the starting points of a taint tracking data flow analysis, and sinks are the end points of a taint tracking data flow analysis.
|
||||
|
||||
Furthermore, the taint tracking queries also need to know how data can flow through elements that are not included in the source code. These are named summaries: they are models of elements that allow us to synthesize the elements flow behavior without having them in the source code. This is especially helpful when using a third party (or the standard) library.
|
||||
|
||||
The models are defined using data extensions where each tuple constitutes a model.
|
||||
A data extension file for Java is a YAML file in the form:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: <name of extensible predicate>
|
||||
data:
|
||||
- <tuple1>
|
||||
- <tuple2>
|
||||
- ...
|
||||
|
||||
Data extensions contribute to the extensible predicates defined in the CodeQL library. For more information on how to define data extensions and extensible predicates as well as how to wire them up, see the :ref:`data-extensions` documentation.
|
||||
|
||||
The CodeQL library for Java exposes the following extensible predicates:
|
||||
|
||||
- **sourceModel**\(package, type, subtypes, name, signature, ext, output, kind, provenance). This is used for **source** models.
|
||||
- **sinkModel**\(package, type, subtypes, name, signature, ext, input, kind, provenance). This is used for **sink** models.
|
||||
- **summaryModel**\(package, type, subtypes, name, signature, ext, input, output, kind, provenance). This is used for **summary** models.
|
||||
- **neutralModel**\(package, type, name, signature, provenance). This is used for **neutral** models, which only have minor impact on the data flow analysis.
|
||||
|
||||
The extensible predicates are populated using data extensions specified in YAML files.
|
||||
|
||||
In the sections below, we will provide examples of how to add tuples to the different extensible predicates.
|
||||
The extensible predicates are used to customize and improve the existing data flow queries, by providing sources, sinks, and flow through (summaries) for library elements.
|
||||
The :ref:`reference-material` section will provide details on the *mini DSLs* that define models for each extensible predicate.
|
||||
|
||||
Example: Taint sink in the **java.sql** package
|
||||
------------------------------------------------
|
||||
|
||||
In this example we will show how to model the argument of the **execute** method as a SQL injection sink.
|
||||
This is the **execute** method in the **Statement** class, which is located in the **java.sql** package.
|
||||
Note that this sink is already added to the CodeQL Java analysis.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
public static void taintsink(Connection conn, String query) throws SQLException {
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute(query); // The argument to this method is a SQL injection sink.
|
||||
}
|
||||
|
||||
We need to add a tuple to the **sinkModel**\(package, type, subtypes, name, signature, ext, input, kind, provenance) extensible predicate. To do this, add the following to a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["java.sql", "Statement", True, "execute", "(String)", "", "Argument[0]", "sql", "manual"]
|
||||
|
||||
|
||||
Since we are adding a new sink, we need to add a tuple to the **sinkModel** extensible predicate.
|
||||
The first five values identify the callable (in this case a method) to be modeled as a sink.
|
||||
|
||||
- The first value **java.sql** is the package name.
|
||||
- The second value **Statement** is the name of the class (type) that contains the method.
|
||||
- The third value **True** is a flag that indicates whether or not the sink also applies to all overrides of the method.
|
||||
- The fourth value **execute** is the method name.
|
||||
- The fifth value **(String)** is the method input type signature.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the **access path**, the **kind**, and the **provenance** (origin) of the sink.
|
||||
|
||||
- The seventh value **Argument[0]** is the **access path** to the first argument passed to the method, which means that this is the location of the sink.
|
||||
- The eighth value **sql** is the kind of the sink. The sink kind is used to define the queries where the sink is in scope. In this case - the SQL injection queries.
|
||||
- The ninth value **manual** is the provenance of the sink, which is used to identify the origin of the sink.
|
||||
|
||||
Example: Taint source from the **java.net** package
|
||||
----------------------------------------------------
|
||||
In this example we show how to model the return value from the **getInputStream** method as a **remote** source.
|
||||
This is the **getInputStream** method in the **Socket** class, which is located in the **java.net** package.
|
||||
Note that this source is already added to the CodeQL Java analysis.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
public static void tainted(Socket socket) throws IOException {
|
||||
InputStream stream = socket.getInputStream(); // The return value of this method is a remote source of taint.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add a tuple to the **sourceModel**\(package, type, subtypes, name, signature, ext, output, kind, provenance) extensible predicate. To do this, add the following to a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["java.net", "Socket", False, "getInputStream", "()", "", "ReturnValue", "remote", "manual"]
|
||||
|
||||
|
||||
Since we are adding a new source, we need to add a tuple to the **sourceModel** extensible predicate.
|
||||
The first five values identify the callable (in this case a method) to be modeled as a source.
|
||||
|
||||
- The first value **java.net** is the package name.
|
||||
- The second value **Socket** is the name of the class (type) that contains the source.
|
||||
- The third value **False** is a flag that indicates whether or not the source also applies to all overrides of the method.
|
||||
- The fourth value **getInputStream** is the method name.
|
||||
- The fifth value **()** is the method input type signature.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the **access path**, the **kind**, and the **provenance** (origin) of the source.
|
||||
|
||||
- The seventh value **ReturnValue** is the access path to the return of the method, which means that it is the return value that should be considered a source of tainted input.
|
||||
- The eighth value **remote** is the kind of the source. The source kind is used to define the queries where the source is in scope. **remote** applies to many of the security related queries as it means a remote source of untrusted data. As an example the SQL injection query uses **remote** sources.
|
||||
- The ninth value **manual** is the provenance of the source, which is used to identify the origin of the source.
|
||||
|
||||
Example: Add flow through the **concat** method
|
||||
------------------------------------------------
|
||||
In this example we show how to model flow through a method for a simple case.
|
||||
This pattern covers many of the cases where we need to define flow through a method.
|
||||
Note that the flow through the **concat** method is already added to the CodeQL Java analysis.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
public static void taintflow(String s1, String s2) {
|
||||
String t = s1.concat(s2); // There is taint flow from s1 and s2 to t.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add tuples to the **summaryModel**\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate. To do this, add the following to a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["java.lang", "String", False, "concat", "(String)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
|
||||
- ["java.lang", "String", False, "concat", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
|
||||
Reasoning:
|
||||
|
||||
Since we are adding flow through a method, we need to add tuples to the **summaryModel** extensible predicate.
|
||||
Each tuple defines flow from one argument to the return value.
|
||||
The first row defines flow from the qualifier (**s1** in the example) to the return value (**t** in the example) and the second row defines flow from the first argument (**s2** in the example) to the return value (**t** in the example).
|
||||
|
||||
The first five values identify the callable (in this case a method) to be modeled as a summary.
|
||||
These are the same for both of the rows above as we are adding two summaries for the same method.
|
||||
|
||||
- The first value **java.lang** is the package name.
|
||||
- The second value **String** is the class (type) name.
|
||||
- The third value **False** is a flag that indicates whether or not the summary also applies to all overrides of the method.
|
||||
- The fourth value **concat** is the method name.
|
||||
- The fifth value **(String)** is the method input type signature.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the **access path**, the **kind**, and the **provenance** (origin) of the summary.
|
||||
|
||||
- The seventh value is the access path to the input (where data flows from). **Argument[this]** is the access path to the qualifier (**s1** in the example) and **Argument[0]** is the access path to the first argument (**s2** in the example).
|
||||
- The eighth value **ReturnValue** is the access path to the output (where data flows to), in this case **ReturnValue**, which means that the input flows to the return value.
|
||||
- The ninth value **taint** is the kind of the flow. **taint** means that taint is propagated through the call.
|
||||
- The tenth value **manual** is the provenance of the summary, which is used to identify the origin of the summary.
|
||||
|
||||
Example: Add flow through the **map** method
|
||||
---------------------------------------------
|
||||
In this example, we will see a more complex example of modeling flow through a method.
|
||||
This pattern shows how to model flow through higher order methods and collection types.
|
||||
Note that the flow through the **map** method is already added to the CodeQL Java analysis.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
public static void taintflow(Stream<String> s) {
|
||||
Stream<String> l = s.map(e -> e.concat("\n"));
|
||||
...
|
||||
}
|
||||
|
||||
To do this, add the following to a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["java.util.stream", "Stream", True, "map", "(Function)", "", "Argument[this].Element", "Argument[0].Parameter[0]", "value", "manual"]
|
||||
- ["java.util.stream", "Stream", True, "map", "(Function)", "", "Argument[0].ReturnValue", "ReturnValue.Element", "value", "manual"]
|
||||
|
||||
|
||||
Since we are adding flow through a method, we need to add tuples to the **summaryModel** extensible predicate.
|
||||
Each tuple defines part of the flow that comprises the total flow through the **map** method.
|
||||
The first five values identify the callable (in this case a method) to be modeled as a summary.
|
||||
These are the same for both of the rows above as we are adding two summaries for the same method.
|
||||
|
||||
- The first value **java.util.stream** is the package name.
|
||||
- The second value **Stream** is the class (type) name.
|
||||
- The third value **True** is a flag that indicates whether or not the summary also applies to all overrides of the method.
|
||||
- The fourth value **map** is the method name.
|
||||
- The fifth value **Function** is the method input type signature.
|
||||
|
||||
The sixth value should be left empty and is out of scope for this documentation.
|
||||
The remaining values are used to define the **access path**, the **kind**, and the **provenance** (origin) of the summary definition.
|
||||
|
||||
- The seventh value is the access path to the **input** (where data flows from).
|
||||
- The eighth value is the access path to the **output** (where data flows to).
|
||||
|
||||
For the first row:
|
||||
|
||||
- The seventh value is **Argument[this].Element**, which is the access path to the elements of the qualifier (the elements of the stream **s** in the example).
|
||||
- The eight value is **Argument[0].Parameter[0]**, which is the access path to the first parameter of the **Function** argument of **map** (the lambda parameter **e** in the example).
|
||||
|
||||
For the second row:
|
||||
|
||||
- The seventh value is **Argument[0].ReturnValue**, which is the access path to the return value of the **Function** argument of **map** (the return value of the lambda in the example).
|
||||
- The eighth value is **ReturnValue.Element**, which is the access path to the elements of the return value of **map** (the elements of the stream **l** in the example).
|
||||
|
||||
For the remaining values for both rows:
|
||||
|
||||
- The ninth value **value** is the kind of the flow. **value** means that the value is preserved.
|
||||
- The tenth value **manual** is the provenance of the summary, which is used to identify the origin of the summary.
|
||||
|
||||
That is, the first row models that there is value flow from the elements of the qualifier stream into the first argument of the function provided to **map** and the second row models that there is value flow from the return value of the function to the elements of the stream returned from **map**.
|
||||
|
||||
Example: Add a **neutral** method
|
||||
----------------------------------
|
||||
In this example we will show how to model the **now** method as being neutral.
|
||||
A neutral model is used to define that there is no flow through a method.
|
||||
Note that the neutral model for the **now** method is already added to the CodeQL Java analysis.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
public static void taintflow() {
|
||||
Instant t = Instant.now(); // There is no flow from now to t.
|
||||
...
|
||||
}
|
||||
|
||||
We need to add a tuple to the **neutralModel**\(package, type, name, signature, provenance) extensible predicate. To do this, add the following to a data extension file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: neutralModel
|
||||
data:
|
||||
- ["java.time", "Instant", "now", "()", "manual"]
|
||||
|
||||
|
||||
Since we are adding a neutral model, we need to add tuples to the **neutralModel** extensible predicate.
|
||||
The first five values identify the callable (in this case a method) to be modeled as a neutral and the fifth value is the provenance (origin) of the neutral.
|
||||
|
||||
- The first value **java.time** is the package name.
|
||||
- The second value **Instant** is the class (type) name.
|
||||
- The third value **now** is the method name.
|
||||
- The fourth value **()** is the method input type signature.
|
||||
- The fifth value **manual** is the provenance of the neutral.
|
||||
|
||||
.. _reference-material:
|
||||
|
||||
Reference material
|
||||
------------------
|
||||
|
||||
The following sections provide reference material for extensible predicates.
|
||||
This includes descriptions of each of the arguments (e.g. access paths, kinds and provenance).
|
||||
|
||||
Extensible predicates
|
||||
---------------------
|
||||
|
||||
Below is a description of the columns for each extensible predicate.
|
||||
Sources, sinks, summaries and neutrals are commonly known as models.
|
||||
The semantics of many of the columns of the extensible predicates are shared.
|
||||
|
||||
The shared columns are:
|
||||
|
||||
- **package**: Name of the package containing the element(s) to be modeled.
|
||||
- **type**: Name of the type containing the element(s) to be modeled.
|
||||
- **subtypes**: A boolean flag indicating whether the model should also apply to all overrides of the selected element(s).
|
||||
- **name**: Name of the element (optional). If this is left blank, it means all elements matching the previous selection criteria.
|
||||
- **signature**: Type signature of the selected element (optional). If this is left blank, it means all elements matching the previous selection criteria.
|
||||
- **ext**: Specifies additional API-graph-like edges (mostly empty) and out of scope for this document.
|
||||
- **provenance**: Provenance (origin) of the model definition.
|
||||
|
||||
The columns **package**, **type**, **subtypes**, **name**, and **signature** are used to select the element(s) that the model applies to.
|
||||
|
||||
The :ref:`access-paths` section describes how access paths are composed.
|
||||
This is the most complicated part of the extensible predicates and the **mini DSL** for access paths is shared across all extensible predicates.
|
||||
|
||||
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Taint source. Most taint tracking queries will use all sources added to this extensible predicate regardless of their kind.
|
||||
|
||||
- **output**: Access path to the source, where the possibly tainted data flows from.
|
||||
- **kind**: Kind of the source.
|
||||
- **provenance**: Provenance (origin) of the source definition.
|
||||
|
||||
As most sources are used by all taint tracking queries there are only a few different source kinds.
|
||||
The following source kinds are supported:
|
||||
|
||||
- **remote**: A remote source of possibly tainted data. This is the most common kind for a source. Sources of this kind are used for almost all taint tracking queries.
|
||||
|
||||
Below is an enumeration of the remaining source kinds, but they are out of scope for this documentation:
|
||||
|
||||
- **contentprovider**, **android-widget**, **android-external-storage-dir**.
|
||||
|
||||
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Taint sink. As opposed to source kinds, there are many different kinds of sinks as these tend to be more query specific.
|
||||
|
||||
- **input**: Access path to the sink, where we want to check if tainted data can flow into.
|
||||
- **kind**: Kind of the sink.
|
||||
|
||||
The following sink kinds are supported:
|
||||
|
||||
- **sql**: A SQL injection vulnerability sink.
|
||||
- **xss**: A cross-site scripting vulnerability sink.
|
||||
- **logging**: A log output sink.
|
||||
|
||||
Below is an enumeration of the remaining sinks, but they are out of scope for this documentation:
|
||||
|
||||
- **open-url**, **jndi-injection**, **ldap**, **jdbc-url**
|
||||
- **mvel**, **xpath**, **groovy**, **ognl-injection**
|
||||
- **intent-start**, **pending-intent-sent**, **url-open-stream**, **url-redirect**
|
||||
- **create-file**, **read-file**, **write-file**, **set-hostname-verifier**
|
||||
- **header-splitting**, **information-leak**, **xslt**, **jexl**
|
||||
- **bean-validation**, **ssti**, **fragment-injection**, **regex-use[**\ `arg`\ **]**
|
||||
|
||||
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Flow through (summary). This extensible predicate is used to model flow through elements.
|
||||
|
||||
- **input**: Access path to the input of the element (where data will flow from to the output).
|
||||
- **output**: Access path to the output of the element (where data will flow to from the input).
|
||||
- **kind**: Kind of the flow through.
|
||||
- **provenance**: Provenance (origin) of the flow through.
|
||||
|
||||
The following kinds are supported:
|
||||
|
||||
- **taint**: This means the output is not necessarily equal to the input, but it was derived from the input in an unrestrictive way. An attacker who controls the input will have significant control over the output as well.
|
||||
- **value**: This means that the output equals the input or a copy of the input such that all of its properties are preserved.
|
||||
|
||||
neutralModel(package, type, name, signature, provenance)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This extensible predicate is not typically needed externally, but included here for completeness.
|
||||
It only has minor impact on the data flow analysis.
|
||||
Manual neutrals are considered high confidence dispatch call targets and can reduce the number of dispatch call targets during data flow analysis (a performance optimization).
|
||||
|
||||
- **provenance**: Provenance (origin) of the flow through.
|
||||
|
||||
.. _access-paths:
|
||||
|
||||
Access paths
|
||||
------------
|
||||
The **input**, and **output** columns consist of a **.**-separated list of components, which is evaluated from left to right, with each step selecting a new set of values derived from the previous set of values.
|
||||
|
||||
The following components are supported:
|
||||
|
||||
- **Argument[**\ `n`\ **]** selects the argument at index `n` (zero-indexed).
|
||||
- **Argument[**\ `this`\ **]** selects the qualifier (instance parameter).
|
||||
- **Argument[**\ `n1..n2`\ **]** selects the arguments in the given range (both ends included).
|
||||
- **Parameter[**\ `n`\ **]** selects the parameter at index `n` (zero-indexed).
|
||||
- **Parameter[**\ `n1..n2`\ **]** selects the parameters in the given range (both ends included).
|
||||
- **ReturnValue** selects the return value.
|
||||
- **Field[**\ `name`\ **]** selects the field with the fully qualified name `name`.
|
||||
- **SyntheticField[**\ `name`\ **]** selects the synthetic field with name `name`.
|
||||
- **SyntheticGlobal[**\ `name`\ **]** selects the synthetic global with name `name`.
|
||||
- **ArrayElement** selects the elements of an array.
|
||||
- **Element** selects the elements of a collection-like container.
|
||||
- **MapKey** selects the element keys of a map.
|
||||
- **MapValue** selects the element values of a map.
|
||||
|
||||
Provenance
|
||||
----------
|
||||
|
||||
The **provenance** column is used to specify the provenance (origin) of the model definition and how the model was verified.
|
||||
The following values are supported:
|
||||
|
||||
- **manual**: The model was manually created and added to the extensible predicate.
|
||||
|
||||
or values in the form **origin-verification**, where origin is one of:
|
||||
|
||||
- **ai**: The model was generated by AI.
|
||||
- **df**: The model was generated by the dataflow model generator.
|
||||
- **tb**: The model was generated by the type based model generator.
|
||||
- **hq**: The model was generated using a heuristic query.
|
||||
|
||||
and verification is one of:
|
||||
|
||||
- **manual**: The model was verified by a human.
|
||||
- **generated**: The model was generated, but not verified by a human.
|
||||
|
||||
The provenance is used to distinguish between models that are manually added (or verified) to the extensible predicate and models that are automatically generated.
|
||||
Furthermore, it impacts the data flow analysis in the following way:
|
||||
|
||||
- A **manual** model takes precedence over **generated** models. If a **manual** model exists for an element then all **generated** models are ignored.
|
||||
- A **generated** model is ignored during analysis, if the source code of the element it is modeling is available.
|
||||
|
||||
That is, generated models are less trusted than manual models and only used if neither source code nor a manual model is available.
|
||||
|
||||
|
||||
.. include:: ../reusables/data-extensions.rst
|
||||
@@ -75,12 +75,12 @@ This query uses ``Call`` and ``Name`` to find calls to the function ``eval`` - w
|
||||
select call, "call to 'eval'."
|
||||
|
||||
The ``Call`` class represents calls in Python. The ``Call.getFunc()`` predicate gets the expression being called. ``Name.getId()`` gets the identifier (as a string) of the ``Name`` expression.
|
||||
Due to the dynamic nature of Python, this query will select any call of the form ``eval(...)`` regardless of whether it is a call to the built-in function ``eval`` or not.
|
||||
In a later tutorial we will see how to use the type-inference library to find calls to the built-in function ``eval`` regardless of name of the variable called.
|
||||
This query will select any call of the form ``eval(...)`` regardless of whether it is a call to the built-in function ``eval`` or not.
|
||||
Due to the dynamic nature of Python, such syntactic queries can be inaccurate. If one is looking for invocations of the built-in function ``eval``,
|
||||
it is preferred to use the API graph, see ":doc:`Using API graphs in Python <using-api-graphs-in-python>`."
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/python-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
.. pull-quote::
|
||||
|
||||
Beta Notice - Unstable API
|
||||
|
||||
Library customization using data extensions is currently in beta and subject to change.
|
||||
|
||||
Breaking changes to this format may occur while in beta.
|
||||
10
docs/codeql/reusables/data-extensions.rst
Normal file
10
docs/codeql/reusables/data-extensions.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
.. _data-extensions:
|
||||
|
||||
Data Extensions
|
||||
===============
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Beta Notice - Internal documentation
|
||||
|
||||
Data extensions are documented internally in a `Google doc <https://docs.google.com/document/d/14IYCHX8wWuU-HTvJ2gPSdXQKHKYbWCHQKOgn8oLaa80>`_.
|
||||
@@ -11,11 +11,11 @@
|
||||
Microsoft extensions (up to VS 2019),
|
||||
|
||||
Arm Compiler 5 [3]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``"
|
||||
C#,C# up to 10.0,"Microsoft Visual Studio up to 2019 with .NET up to 4.8,
|
||||
C#,C# up to 11,"Microsoft Visual Studio up to 2019 with .NET up to 4.8,
|
||||
|
||||
.NET Core up to 3.1
|
||||
|
||||
.NET 5, .NET 6","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
|
||||
.NET 5, .NET 6, .NET 7","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
|
||||
Go (aka Golang), "Go up to 1.20", "Go 1.11 or more recent", ``.go``
|
||||
Java,"Java 7 to 20 [4]_","javac (OpenJDK and Oracle JDK),
|
||||
|
||||
|
||||
4
go/ql/lib/change-notes/2023-03-28-dataflow-rm-footgun.md
Normal file
4
go/ql/lib/change-notes/2023-03-28-dataflow-rm-footgun.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed some accidental predicate visibility in the backwards-compatible wrapper for data flow configurations. In particular `DataFlow::hasFlowPath`, `DataFlow::hasFlow`, `DataFlow::hasFlowTo`, and `DataFlow::hasFlowToExpr` were accidentally exposed in a single version.
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -33,17 +33,15 @@ freemarker.cache,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,
|
||||
freemarker.template,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,
|
||||
groovy.lang,26,,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
groovy.util,5,,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
hudson.model,4,,1,,2,,,,,,,,,,,,,1,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
hudson.os,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
hudson.remoting,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
hudson.util,4,,1,,3,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
hudson,44,,16,,19,,,,,,,,,,,,,6,,17,,,,,,,,,,,,,2,,,,,,,,16,
|
||||
io.netty.bootstrap,3,,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
io.netty.channel,9,,,,,,,,,,,,,,,,,9,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
io.netty.handler.codec.http,3,,1,,,,,,,,,,,,,,,2,,1,,,,,,,,,,,,,,,,,,,,,1,
|
||||
io.netty.buffer,,,207,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,130,77
|
||||
io.netty.channel,9,2,,,,,,,,,,,,,,,,9,,,,,,,,,,,,,,,,,,,,,,2,,
|
||||
io.netty.handler.codec,3,13,260,,,,,,,,,,,,,,,2,,1,,,,,,,,,,,,,,,,,,,,13,144,116
|
||||
io.netty.handler.ssl,2,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,
|
||||
io.netty.handler.stream,1,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,
|
||||
io.netty.resolver,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
io.netty.util.internal,2,,2,,1,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,2,
|
||||
io.netty.util,2,,23,,1,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,21,2
|
||||
jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,,
|
||||
jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23
|
||||
jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,
|
||||
|
||||
|
@@ -22,6 +22,6 @@ Java framework & library support
|
||||
Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,1,,4,,1,1,2
|
||||
Kotlin Standard Library,``kotlin*``,,1835,12,10,,,,,,2
|
||||
`Spring <https://spring.io/>`_,``org.springframework.*``,29,480,101,,,,19,14,,29
|
||||
Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.util``, ``hudson.model``, ``hudson.os``, ``hudson.remoting``, ``hudson.util``, ``io.netty.bootstrap``, ``io.netty.channel``, ``io.netty.handler.codec.http``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util.internal``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",60,314,328,12,,,18,18,,28
|
||||
Totals,,217,8544,1647,150,6,10,113,33,1,113
|
||||
Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.util``, ``hudson``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",75,813,364,26,,,18,18,,33
|
||||
Totals,,232,9043,1683,164,6,10,113,33,1,118
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed some accidental predicate visibility in the backwards-compatible wrapper for data flow configurations. In particular `DataFlow::hasFlowPath`, `DataFlow::hasFlow`, `DataFlow::hasFlowTo`, and `DataFlow::hasFlowToExpr` were accidentally exposed in a single version.
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
128
java/ql/lib/semmle/code/java/security/InsecureLdapAuth.qll
Normal file
128
java/ql/lib/semmle/code/java/security/InsecureLdapAuth.qll
Normal file
@@ -0,0 +1,128 @@
|
||||
/** Provides classes to reason about insecure LDAP authentication. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.frameworks.Networking
|
||||
private import semmle.code.java.frameworks.Jndi
|
||||
|
||||
/**
|
||||
* An expression that represents an insecure (non-SSL, non-private) LDAP URL.
|
||||
*/
|
||||
class InsecureLdapUrl extends Expr {
|
||||
InsecureLdapUrl() {
|
||||
this instanceof InsecureLdapUrlLiteral
|
||||
or
|
||||
// Concatentation of insecure protcol and non-private host:
|
||||
// protocol + host + ...
|
||||
exists(AddExpr e, CompileTimeConstantExpr protocol, Expr rest, Expr host |
|
||||
e = this and
|
||||
protocol = e.getLeftOperand() and
|
||||
rest = e.getRightOperand() and
|
||||
if rest instanceof AddExpr then host = rest.(AddExpr).getLeftOperand() else host = rest
|
||||
|
|
||||
protocol.getStringValue() = "ldap://" and
|
||||
not exists(string hostString | hostString = getHostname(host) |
|
||||
hostString.length() = 0 or // Empty host is loopback address
|
||||
hostString instanceof PrivateHostName
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sink representing the construction of a `DirContextEnvironment`.
|
||||
*/
|
||||
class InsecureLdapUrlSink extends DataFlow::Node {
|
||||
InsecureLdapUrlSink() {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType().getAnAncestor() instanceof TypeDirContext and
|
||||
this.asExpr() = cc.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`.
|
||||
*/
|
||||
predicate isBasicAuthEnv(MethodAccess ma) {
|
||||
hasFieldValueEnv(ma, "java.naming.security.authentication", "simple") or
|
||||
hasFieldNameEnv(ma, "SECURITY_AUTHENTICATION", "simple")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets `java.naming.security.protocol` (also known as `Context.SECURITY_PROTOCOL`) to `ssl` in some `Hashtable`.
|
||||
*/
|
||||
predicate isSslEnv(MethodAccess ma) {
|
||||
hasFieldValueEnv(ma, "java.naming.security.protocol", "ssl") or
|
||||
hasFieldNameEnv(ma, "SECURITY_PROTOCOL", "ssl")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` writes the `java.naming.provider.url` (also known as `Context.PROVIDER_URL`) key of a `Hashtable`.
|
||||
*/
|
||||
predicate isProviderUrlSetter(MethodAccess ma) {
|
||||
ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
ma.getMethod().hasName(["put", "setProperty"]) and
|
||||
(
|
||||
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url"
|
||||
or
|
||||
exists(Field f |
|
||||
ma.getArgument(0) = f.getAnAccess() and
|
||||
f.hasName("PROVIDER_URL") and
|
||||
f.getDeclaringType() instanceof TypeNamingContext
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An insecure (non-SSL, non-private) LDAP URL string literal.
|
||||
*/
|
||||
private class InsecureLdapUrlLiteral extends StringLiteral {
|
||||
InsecureLdapUrlLiteral() {
|
||||
// Match connection strings with the LDAP protocol and without private IP addresses to reduce false positives.
|
||||
exists(string s | this.getValue() = s |
|
||||
s.regexpMatch("(?i)ldap://[\\[a-zA-Z0-9].*") and
|
||||
not s.substring(7, s.length()) instanceof PrivateHostName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `java.util.Hashtable`. */
|
||||
private class TypeHashtable extends Class {
|
||||
TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") }
|
||||
}
|
||||
|
||||
/** Get the string value of an expression representing a hostname. */
|
||||
private string getHostname(Expr expr) {
|
||||
result = expr.(CompileTimeConstantExpr).getStringValue() or
|
||||
result =
|
||||
expr.(VarAccess).getVariable().getAnAssignedValue().(CompileTimeConstantExpr).getStringValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets `fieldValue` to `envValue` in some `Hashtable`.
|
||||
*/
|
||||
bindingset[fieldValue, envValue]
|
||||
private predicate hasFieldValueEnv(MethodAccess ma, string fieldValue, string envValue) {
|
||||
// environment.put("java.naming.security.authentication", "simple")
|
||||
ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
ma.getMethod().hasName(["put", "setProperty"]) and
|
||||
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = fieldValue and
|
||||
ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets attribute name `fieldName` to `envValue` in some `Hashtable`.
|
||||
*/
|
||||
bindingset[fieldName, envValue]
|
||||
private predicate hasFieldNameEnv(MethodAccess ma, string fieldName, string envValue) {
|
||||
// environment.put(Context.SECURITY_AUTHENTICATION, "simple")
|
||||
ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
ma.getMethod().hasName(["put", "setProperty"]) and
|
||||
exists(Field f |
|
||||
ma.getArgument(0) = f.getAnAccess() and
|
||||
f.hasName(fieldName) and
|
||||
f.getDeclaringType() instanceof TypeNamingContext
|
||||
) and
|
||||
ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/** Provides dataflow configurations to reason about insecure LDAP authentication. */
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.frameworks.Jndi
|
||||
import semmle.code.java.security.InsecureLdapAuth
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for `ldap://` URL in LDAP authentication.
|
||||
*/
|
||||
module InsecureLdapUrlConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof InsecureLdapUrl }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureLdapUrlSink }
|
||||
|
||||
/** Method call of `env.put()`. */
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(MethodAccess ma |
|
||||
pred.asExpr() = ma.getArgument(1) and
|
||||
isProviderUrlSetter(ma) and
|
||||
succ.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module InsecureLdapUrlFlow = TaintTracking::Global<InsecureLdapUrlConfig>;
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for `simple` basic-authentication in LDAP configuration.
|
||||
*/
|
||||
private module BasicAuthConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(MethodAccess ma |
|
||||
isBasicAuthEnv(ma) and
|
||||
ma.getQualifier() = src.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureLdapUrlSink }
|
||||
}
|
||||
|
||||
module BasicAuthFlow = DataFlow::Global<BasicAuthConfig>;
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for `ssl` configuration in LDAP authentication.
|
||||
*/
|
||||
private module RequiresSslConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(MethodAccess ma |
|
||||
isSslEnv(ma) and
|
||||
ma.getQualifier() = src.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureLdapUrlSink }
|
||||
}
|
||||
|
||||
module RequiresSslFlow = DataFlow::Global<RequiresSslConfig>;
|
||||
51
java/ql/src/Security/CWE/CWE-522/InsecureLdapAuth.qhelp
Normal file
51
java/ql/src/Security/CWE/CWE-522/InsecureLdapAuth.qhelp
Normal file
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
When using the Java LDAP API to perform LDAPv3-style extended operations
|
||||
and controls, a context with connection properties including user
|
||||
credentials is started. Transmission of LDAP credentials in cleartext
|
||||
allows remote attackers to obtain sensitive information by sniffing the
|
||||
network.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Use the <code>ldaps://</code> protocol to send credentials through SSL or
|
||||
use SASL authentication.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
In the following (bad) example, a <code>ldap://</code> URL is used and
|
||||
credentials will be sent in plaintext.
|
||||
</p>
|
||||
<sample src="LdapAuthUseLdap.java"/>
|
||||
|
||||
<p>
|
||||
In the following (good) example, a <code>ldaps://</code> URL is used so
|
||||
credentials will be encrypted with SSL.
|
||||
</p>
|
||||
<sample src="LdapAuthUseLdaps.java"/>
|
||||
|
||||
<p>
|
||||
In the following (good) example, a <code>ldap://</code> URL is used, but
|
||||
SASL authentication is enabled so that the credentials will be encrypted.
|
||||
</p>
|
||||
<sample src="LdapEnableSasl.java"/>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Oracle:
|
||||
<a href="https://docs.oracle.com/javase/jndi/tutorial/ldap/misc/url.html">LDAP and LDAPS URLs</a>
|
||||
</li>
|
||||
<li>
|
||||
Oracle:
|
||||
<a href="https://docs.oracle.com/javase/tutorial/jndi/ldap/simple.html">Simple authentication</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
25
java/ql/src/Security/CWE/CWE-522/InsecureLdapAuth.ql
Normal file
25
java/ql/src/Security/CWE/CWE-522/InsecureLdapAuth.ql
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @name Insecure LDAP authentication
|
||||
* @description LDAP authentication with credentials sent in cleartext makes sensitive information vulnerable to remote attackers
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @precision medium
|
||||
* @id java/insecure-ldap-auth
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-522
|
||||
* external/cwe/cwe-319
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.InsecureLdapAuthQuery
|
||||
import InsecureLdapUrlFlow::PathGraph
|
||||
|
||||
from InsecureLdapUrlFlow::PathNode source, InsecureLdapUrlFlow::PathNode sink
|
||||
where
|
||||
InsecureLdapUrlFlow::flowPath(source, sink) and
|
||||
BasicAuthFlow::flowTo(sink.getNode()) and
|
||||
not RequiresSslFlow::flowTo(sink.getNode())
|
||||
select sink.getNode(), source, sink, "Insecure LDAP authentication from $@.", source.getNode(),
|
||||
"LDAP connection string"
|
||||
9
java/ql/src/Security/CWE/CWE-522/LdapAuthUseLdap.java
Normal file
9
java/ql/src/Security/CWE/CWE-522/LdapAuthUseLdap.java
Normal file
@@ -0,0 +1,9 @@
|
||||
String ldapUrl = "ldap://ad.your-server.com:389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
environment.put(Context.SECURITY_PRINCIPAL, ldapUserName);
|
||||
environment.put(Context.SECURITY_CREDENTIALS, password);
|
||||
DirContext dirContext = new InitialDirContext(environment);
|
||||
9
java/ql/src/Security/CWE/CWE-522/LdapAuthUseLdaps.java
Normal file
9
java/ql/src/Security/CWE/CWE-522/LdapAuthUseLdaps.java
Normal file
@@ -0,0 +1,9 @@
|
||||
String ldapUrl = "ldaps://ad.your-server.com:636";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
environment.put(Context.SECURITY_PRINCIPAL, ldapUserName);
|
||||
environment.put(Context.SECURITY_CREDENTIALS, password);
|
||||
DirContext dirContext = new InitialDirContext(environment);
|
||||
9
java/ql/src/Security/CWE/CWE-522/LdapEnableSasl.java
Normal file
9
java/ql/src/Security/CWE/CWE-522/LdapEnableSasl.java
Normal file
@@ -0,0 +1,9 @@
|
||||
String ldapUrl = "ldap://ad.your-server.com:389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5 GSSAPI");
|
||||
environment.put(Context.SECURITY_PRINCIPAL, ldapUserName);
|
||||
environment.put(Context.SECURITY_CREDENTIALS, password);
|
||||
DirContext dirContext = new InitialDirContext(environment);
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The query `java/insecure-ldap-auth` has been promoted from experimental to the main query pack. This query detects transmission of cleartext credentials in LDAP authentication. Insecure LDAP authentication causes sensitive information to be vulnerable to remote attackers. This query was originally [submitted as an experimental query by @luchua-bc](https://github.com/github/codeql/pull/4854)
|
||||
@@ -1,24 +0,0 @@
|
||||
public class InsecureLdapAuth {
|
||||
/** LDAP authentication */
|
||||
public DirContext ldapAuth(String ldapUserName, String password) {
|
||||
{
|
||||
// BAD: LDAP authentication in cleartext
|
||||
String ldapUrl = "ldap://ad.your-server.com:389";
|
||||
}
|
||||
|
||||
{
|
||||
// GOOD: LDAPS authentication over SSL
|
||||
String ldapUrl = "ldaps://ad.your-server.com:636";
|
||||
}
|
||||
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
environment.put(Context.SECURITY_PRINCIPAL, ldapUserName);
|
||||
environment.put(Context.SECURITY_CREDENTIALS, password);
|
||||
DirContext dirContext = new InitialDirContext(environment);
|
||||
return dirContext;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>When using the Java LDAP API to perform LDAPv3-style extended operations and controls, a context with connection properties including user credentials is started. Transmission of LDAP credentials in cleartext allows remote attackers to obtain sensitive information by sniffing the network.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Use LDAPS to send credentials through SSL or use SASL authentication.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following example shows two ways of using LDAP authentication. In the 'BAD' case, the credentials are transmitted in cleartext. In the 'GOOD' case, the credentials are transmitted over SSL.</p>
|
||||
<sample src="InsecureLdapAuth.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Oracle:
|
||||
<a href="https://docs.oracle.com/javase/jndi/tutorial/ldap/misc/url.html">LDAP and LDAPS URLs</a>
|
||||
</li>
|
||||
<li>
|
||||
Oracle:
|
||||
<a href="https://docs.oracle.com/javase/tutorial/jndi/ldap/simple.html">Simple authentication</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,211 +0,0 @@
|
||||
/**
|
||||
* @name Insecure LDAP authentication
|
||||
* @description LDAP authentication with credentials sent in cleartext.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insecure-ldap-auth
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-522
|
||||
* external/cwe/cwe-319
|
||||
*/
|
||||
|
||||
import java
|
||||
import DataFlow
|
||||
import semmle.code.java.frameworks.Jndi
|
||||
import semmle.code.java.frameworks.Networking
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Insecure (non-SSL, non-private) LDAP URL string literal.
|
||||
*/
|
||||
class InsecureLdapUrlLiteral extends StringLiteral {
|
||||
InsecureLdapUrlLiteral() {
|
||||
// Match connection strings with the LDAP protocol and without private IP addresses to reduce false positives.
|
||||
exists(string s | this.getValue() = s |
|
||||
s.regexpMatch("(?i)ldap://[\\[a-zA-Z0-9].*") and
|
||||
not s.substring(7, s.length()) instanceof PrivateHostName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `java.util.Hashtable`. */
|
||||
class TypeHashtable extends Class {
|
||||
TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a non-private LDAP string is concatenated from both protocol and host.
|
||||
*/
|
||||
predicate concatInsecureLdapString(Expr protocol, Expr host) {
|
||||
protocol.(CompileTimeConstantExpr).getStringValue() = "ldap://" and
|
||||
not exists(string hostString |
|
||||
hostString = host.(CompileTimeConstantExpr).getStringValue() or
|
||||
hostString =
|
||||
host.(VarAccess).getVariable().getAnAssignedValue().(CompileTimeConstantExpr).getStringValue()
|
||||
|
|
||||
hostString.length() = 0 or // Empty host is loopback address
|
||||
hostString instanceof PrivateHostName
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the leftmost operand in a concatenated string */
|
||||
Expr getLeftmostConcatOperand(Expr expr) {
|
||||
if expr instanceof AddExpr
|
||||
then result = getLeftmostConcatOperand(expr.(AddExpr).getLeftOperand())
|
||||
else result = expr
|
||||
}
|
||||
|
||||
/**
|
||||
* String concatenated with `InsecureLdapUrlLiteral`.
|
||||
*/
|
||||
class InsecureLdapUrl extends Expr {
|
||||
InsecureLdapUrl() {
|
||||
this instanceof InsecureLdapUrlLiteral
|
||||
or
|
||||
concatInsecureLdapString(this.(AddExpr).getLeftOperand(),
|
||||
getLeftmostConcatOperand(this.(AddExpr).getRightOperand()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` writes the `java.naming.provider.url` (also known as `Context.PROVIDER_URL`) key of a `Hashtable`.
|
||||
*/
|
||||
predicate isProviderUrlSetter(MethodAccess ma) {
|
||||
ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
ma.getMethod().hasName(["put", "setProperty"]) and
|
||||
(
|
||||
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url"
|
||||
or
|
||||
exists(Field f |
|
||||
ma.getArgument(0) = f.getAnAccess() and
|
||||
f.hasName("PROVIDER_URL") and
|
||||
f.getDeclaringType() instanceof TypeNamingContext
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets `fieldValue` to `envValue` in some `Hashtable`.
|
||||
*/
|
||||
bindingset[fieldValue, envValue]
|
||||
predicate hasFieldValueEnv(MethodAccess ma, string fieldValue, string envValue) {
|
||||
// environment.put("java.naming.security.authentication", "simple")
|
||||
ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
ma.getMethod().hasName(["put", "setProperty"]) and
|
||||
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = fieldValue and
|
||||
ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets attribute name `fieldName` to `envValue` in some `Hashtable`.
|
||||
*/
|
||||
bindingset[fieldName, envValue]
|
||||
predicate hasFieldNameEnv(MethodAccess ma, string fieldName, string envValue) {
|
||||
// environment.put(Context.SECURITY_AUTHENTICATION, "simple")
|
||||
ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
ma.getMethod().hasName(["put", "setProperty"]) and
|
||||
exists(Field f |
|
||||
ma.getArgument(0) = f.getAnAccess() and
|
||||
f.hasName(fieldName) and
|
||||
f.getDeclaringType() instanceof TypeNamingContext
|
||||
) and
|
||||
ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`.
|
||||
*/
|
||||
predicate isBasicAuthEnv(MethodAccess ma) {
|
||||
hasFieldValueEnv(ma, "java.naming.security.authentication", "simple") or
|
||||
hasFieldNameEnv(ma, "SECURITY_AUTHENTICATION", "simple")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` sets `java.naming.security.protocol` (also known as `Context.SECURITY_PROTOCOL`) to `ssl` in some `Hashtable`.
|
||||
*/
|
||||
predicate isSslEnv(MethodAccess ma) {
|
||||
hasFieldValueEnv(ma, "java.naming.security.protocol", "ssl") or
|
||||
hasFieldNameEnv(ma, "SECURITY_PROTOCOL", "ssl")
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for `ldap://` URL in LDAP authentication.
|
||||
*/
|
||||
class InsecureUrlFlowConfig extends TaintTracking::Configuration {
|
||||
InsecureUrlFlowConfig() { this = "InsecureLdapAuth:InsecureUrlFlowConfig" }
|
||||
|
||||
/** Source of `ldap://` connection string. */
|
||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof InsecureLdapUrl }
|
||||
|
||||
/** Sink of directory context creation. */
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType().getAnAncestor() instanceof TypeDirContext and
|
||||
sink.asExpr() = cc.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
/** Method call of `env.put()`. */
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(MethodAccess ma |
|
||||
pred.asExpr() = ma.getArgument(1) and
|
||||
isProviderUrlSetter(ma) and
|
||||
succ.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for `simple` basic-authentication in LDAP configuration.
|
||||
*/
|
||||
class BasicAuthFlowConfig extends DataFlow::Configuration {
|
||||
BasicAuthFlowConfig() { this = "InsecureLdapAuth:BasicAuthFlowConfig" }
|
||||
|
||||
/** Source of `simple` configuration. */
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
exists(MethodAccess ma |
|
||||
isBasicAuthEnv(ma) and ma.getQualifier() = src.(PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/** Sink of directory context creation. */
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType().getAnAncestor() instanceof TypeDirContext and
|
||||
sink.asExpr() = cc.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for `ssl` configuration in LDAP authentication.
|
||||
*/
|
||||
class SslFlowConfig extends DataFlow::Configuration {
|
||||
SslFlowConfig() { this = "InsecureLdapAuth:SSLFlowConfig" }
|
||||
|
||||
/** Source of `ssl` configuration. */
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
exists(MethodAccess ma |
|
||||
isSslEnv(ma) and ma.getQualifier() = src.(PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/** Sink of directory context creation. */
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(ConstructorCall cc |
|
||||
cc.getConstructedType().getAnAncestor() instanceof TypeDirContext and
|
||||
sink.asExpr() = cc.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureUrlFlowConfig config
|
||||
where
|
||||
config.hasFlowPath(source, sink) and
|
||||
exists(BasicAuthFlowConfig bc | bc.hasFlowTo(sink.getNode())) and
|
||||
not exists(SslFlowConfig sc | sc.hasFlowTo(sink.getNode()))
|
||||
select sink.getNode(), source, sink, "Insecure LDAP authentication from $@.", source.getNode(),
|
||||
"LDAP connection string"
|
||||
@@ -1,111 +0,0 @@
|
||||
edges
|
||||
| InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:20:49:20:59 | environment |
|
||||
| InsecureLdapAuth.java:15:3:15:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:20:49:20:59 | environment |
|
||||
| InsecureLdapAuth.java:15:41:15:47 | ldapUrl : String | InsecureLdapAuth.java:15:3:15:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:17:3:17:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:20:49:20:59 | environment |
|
||||
| InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:34:49:34:59 | environment |
|
||||
| InsecureLdapAuth.java:29:3:29:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:34:49:34:59 | environment |
|
||||
| InsecureLdapAuth.java:29:41:29:47 | ldapUrl : String | InsecureLdapAuth.java:29:3:29:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:31:3:31:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:34:49:34:59 | environment |
|
||||
| InsecureLdapAuth.java:45:3:45:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:48:49:48:59 | environment |
|
||||
| InsecureLdapAuth.java:53:20:53:50 | "ldap://ad.your-server.com:636" : String | InsecureLdapAuth.java:57:41:57:47 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:53:20:53:50 | "ldap://ad.your-server.com:636" : String | InsecureLdapAuth.java:63:49:63:59 | environment |
|
||||
| InsecureLdapAuth.java:57:3:57:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:63:49:63:59 | environment |
|
||||
| InsecureLdapAuth.java:57:41:57:47 | ldapUrl : String | InsecureLdapAuth.java:57:3:57:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:59:3:59:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:63:49:63:59 | environment |
|
||||
| InsecureLdapAuth.java:62:3:62:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:63:49:63:59 | environment |
|
||||
| InsecureLdapAuth.java:68:20:68:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:72:41:72:47 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:68:20:68:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:77:49:77:59 | environment |
|
||||
| InsecureLdapAuth.java:72:3:72:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:77:49:77:59 | environment |
|
||||
| InsecureLdapAuth.java:72:41:72:47 | ldapUrl : String | InsecureLdapAuth.java:72:3:72:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:88:3:88:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:91:49:91:59 | environment |
|
||||
| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:41:100:47 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:105:59:105:69 | environment |
|
||||
| InsecureLdapAuth.java:100:3:100:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:105:59:105:69 | environment |
|
||||
| InsecureLdapAuth.java:100:41:100:47 | ldapUrl : String | InsecureLdapAuth.java:100:3:100:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:102:3:102:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:105:59:105:69 | environment |
|
||||
| InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:115:47:115:53 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:120:49:120:59 | environment |
|
||||
| InsecureLdapAuth.java:115:3:115:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:120:49:120:59 | environment |
|
||||
| InsecureLdapAuth.java:115:47:115:53 | ldapUrl : String | InsecureLdapAuth.java:115:3:115:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:117:3:117:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:120:49:120:59 | environment |
|
||||
| InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:135:20:135:39 | ... + ... : String | InsecureLdapAuth.java:140:41:140:47 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:135:20:135:39 | ... + ... : String | InsecureLdapAuth.java:142:50:142:60 | environment |
|
||||
| InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | InsecureLdapAuth.java:142:50:142:60 | environment |
|
||||
| InsecureLdapAuth.java:140:3:140:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:142:50:142:60 | environment |
|
||||
| InsecureLdapAuth.java:140:41:140:47 | ldapUrl : String | InsecureLdapAuth.java:140:3:140:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | InsecureLdapAuth.java:142:50:142:60 | environment |
|
||||
| InsecureLdapAuth.java:147:20:147:39 | ... + ... : String | InsecureLdapAuth.java:151:41:151:47 | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:147:20:147:39 | ... + ... : String | InsecureLdapAuth.java:153:50:153:60 | environment |
|
||||
| InsecureLdapAuth.java:151:3:151:13 | environment [post update] [<map.value>] : String | InsecureLdapAuth.java:153:50:153:60 | environment |
|
||||
| InsecureLdapAuth.java:151:41:151:47 | ldapUrl : String | InsecureLdapAuth.java:151:3:151:13 | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable | InsecureLdapAuth.java:153:50:153:60 | environment |
|
||||
nodes
|
||||
| InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String |
|
||||
| InsecureLdapAuth.java:15:3:15:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:15:41:15:47 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:17:3:17:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:20:49:20:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:20:49:20:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| InsecureLdapAuth.java:29:3:29:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:29:41:29:47 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:31:3:31:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:34:49:34:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:34:49:34:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:45:3:45:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:48:49:48:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:53:20:53:50 | "ldap://ad.your-server.com:636" : String | semmle.label | "ldap://ad.your-server.com:636" : String |
|
||||
| InsecureLdapAuth.java:57:3:57:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:57:41:57:47 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:59:3:59:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:62:3:62:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:68:20:68:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String |
|
||||
| InsecureLdapAuth.java:72:3:72:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:72:41:72:47 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:77:49:77:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:88:3:88:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:91:49:91:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String |
|
||||
| InsecureLdapAuth.java:100:3:100:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:100:41:100:47 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:102:3:102:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:105:59:105:69 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:105:59:105:69 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String |
|
||||
| InsecureLdapAuth.java:115:3:115:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:115:47:115:53 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:117:3:117:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:120:49:120:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:120:49:120:59 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | semmle.label | env [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | semmle.label | env [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:135:20:135:39 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:140:3:140:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:140:41:140:47 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:142:50:142:60 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:142:50:142:60 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:142:50:142:60 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:147:20:147:39 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| InsecureLdapAuth.java:151:3:151:13 | environment [post update] [<map.value>] : String | semmle.label | environment [post update] [<map.value>] : String |
|
||||
| InsecureLdapAuth.java:151:41:151:47 | ldapUrl : String | semmle.label | ldapUrl : String |
|
||||
| InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable |
|
||||
| InsecureLdapAuth.java:153:50:153:60 | environment | semmle.label | environment |
|
||||
| InsecureLdapAuth.java:153:50:153:60 | environment | semmle.label | environment |
|
||||
subpaths
|
||||
#select
|
||||
| InsecureLdapAuth.java:20:49:20:59 | environment | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:20:49:20:59 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" | LDAP connection string |
|
||||
| InsecureLdapAuth.java:34:49:34:59 | environment | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:34:49:34:59 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:25:20:25:39 | ... + ... | LDAP connection string |
|
||||
| InsecureLdapAuth.java:105:59:105:69 | environment | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:105:59:105:69 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" | LDAP connection string |
|
||||
| InsecureLdapAuth.java:120:49:120:59 | environment | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:120:49:120:59 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" | LDAP connection string |
|
||||
| InsecureLdapAuth.java:153:50:153:60 | environment | InsecureLdapAuth.java:147:20:147:39 | ... + ... : String | InsecureLdapAuth.java:153:50:153:60 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:147:20:147:39 | ... + ... | LDAP connection string |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql
|
||||
@@ -11,13 +11,13 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://ad.your-server.com:389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
environment.put(Context.SECURITY_PRINCIPAL, ldapUserName);
|
||||
environment.put(Context.SECURITY_CREDENTIALS, password);
|
||||
DirContext dirContext = new InitialDirContext(environment);
|
||||
DirContext dirContext = new InitialDirContext(environment); // $ hasInsecureLdapAuth
|
||||
}
|
||||
|
||||
// BAD - Test LDAP authentication in cleartext using `DirContext`.
|
||||
@@ -25,13 +25,13 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://"+serverName+":389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
environment.put(Context.SECURITY_PRINCIPAL, ldapUserName);
|
||||
environment.put(Context.SECURITY_CREDENTIALS, password);
|
||||
DirContext dirContext = new InitialDirContext(environment);
|
||||
DirContext dirContext = new InitialDirContext(environment); // $ hasInsecureLdapAuth
|
||||
}
|
||||
|
||||
// GOOD - Test LDAP authentication over SSL.
|
||||
@@ -39,7 +39,7 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldaps://ad.your-server.com:636";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
@@ -53,7 +53,7 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://ad.your-server.com:636";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
@@ -68,7 +68,7 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://ad.your-server.com:389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5 GSSAPI");
|
||||
@@ -82,7 +82,7 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://localhost:389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
@@ -96,14 +96,14 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://ad.your-server.com:389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
environment.put(Context.REFERRAL, "follow");
|
||||
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
environment.put(Context.SECURITY_PRINCIPAL, ldapUserName);
|
||||
environment.put(Context.SECURITY_CREDENTIALS, password);
|
||||
InitialLdapContext ldapContext = new InitialLdapContext(environment, null);
|
||||
}
|
||||
InitialLdapContext ldapContext = new InitialLdapContext(environment, null); // $ hasInsecureLdapAuth
|
||||
}
|
||||
|
||||
|
||||
// BAD - Test LDAP authentication in cleartext using `DirContext` and string literals.
|
||||
@@ -111,13 +111,13 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://ad.your-server.com:389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put("java.naming.factory.initial",
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put("java.naming.provider.url", ldapUrl);
|
||||
environment.put("java.naming.referral", "follow");
|
||||
environment.put("java.naming.security.authentication", "simple");
|
||||
environment.put("java.naming.security.principal", ldapUserName);
|
||||
environment.put("java.naming.security.credentials", password);
|
||||
DirContext dirContext = new InitialDirContext(environment);
|
||||
DirContext dirContext = new InitialDirContext(environment); // $ hasInsecureLdapAuth
|
||||
}
|
||||
|
||||
private void setSSL(Hashtable env) {
|
||||
@@ -136,7 +136,7 @@ public class InsecureLdapAuth {
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
setSSL(environment);
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
setBasicAuth(environment, ldapUserName, password);
|
||||
DirContext dirContext = new InitialLdapContext(environment, null);
|
||||
@@ -147,9 +147,9 @@ public class InsecureLdapAuth {
|
||||
String ldapUrl = "ldap://"+serverName+":389";
|
||||
Hashtable<String, String> environment = new Hashtable<String, String>();
|
||||
environment.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
environment.put(Context.PROVIDER_URL, ldapUrl);
|
||||
setBasicAuth(environment, ldapUserName, password);
|
||||
DirContext dirContext = new InitialLdapContext(environment, null);
|
||||
DirContext dirContext = new InitialLdapContext(environment, null); // $ hasInsecureLdapAuth
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import java
|
||||
import semmle.code.java.security.InsecureLdapAuthQuery
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class InsecureLdapAuthenticationTest extends InlineExpectationsTest {
|
||||
InsecureLdapAuthenticationTest() { this = "InsecureLdapAuthentication" }
|
||||
|
||||
override string getARelevantTag() { result = "hasInsecureLdapAuth" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasInsecureLdapAuth" and
|
||||
exists(DataFlow::Node sink | InsecureLdapUrlFlow::flowTo(sink) |
|
||||
BasicAuthFlow::flowTo(sink) and
|
||||
not RequiresSslFlow::flowTo(sink) and
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -243,6 +243,11 @@ module AccessPath {
|
||||
root.isGlobal()
|
||||
)
|
||||
or
|
||||
exists(Assignment assign |
|
||||
fromReference(assign.getLhs().flow(), root) = result and
|
||||
node = assign.getRhs().flow()
|
||||
)
|
||||
or
|
||||
exists(FunctionDeclStmt fun |
|
||||
node = DataFlow::valueNode(fun) and
|
||||
result = fun.getIdentifier().(GlobalVarDecl).getName() and
|
||||
|
||||
@@ -85,6 +85,7 @@ test_getAFunctionValue
|
||||
| es2015.js:35:1:35:3 | sum | es2015.js:31:1:33:1 | functio ... +y+z;\\n} |
|
||||
| es2015.js:36:1:36:3 | sum | es2015.js:31:1:33:1 | functio ... +y+z;\\n} |
|
||||
| m2.js:2:6:2:18 | function() {} | m2.js:2:6:2:18 | function() {} |
|
||||
| m.js:1:1:1:9 | exports.f | m.js:1:13:1:25 | function() {} |
|
||||
| m.js:1:1:1:25 | exports ... on() {} | m.js:1:13:1:25 | function() {} |
|
||||
| m.js:1:13:1:25 | function() {} | m.js:1:13:1:25 | function() {} |
|
||||
| m.js:2:1:2:9 | exports.f | m.js:1:13:1:25 | function() {} |
|
||||
@@ -100,16 +101,19 @@ test_getAFunctionValue
|
||||
| protoclass.js:3:10:3:10 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} |
|
||||
| protoclass.js:4:3:4:11 | this.init | protoclass.js:7:20:11:1 | functio ... m();\\n} |
|
||||
| protoclass.js:7:1:7:1 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} |
|
||||
| protoclass.js:7:1:7:16 | F.prototype.init | protoclass.js:7:20:11:1 | functio ... m();\\n} |
|
||||
| protoclass.js:7:1:11:1 | F.proto ... m();\\n} | protoclass.js:7:20:11:1 | functio ... m();\\n} |
|
||||
| protoclass.js:7:20:11:1 | functio ... m();\\n} | protoclass.js:7:20:11:1 | functio ... m();\\n} |
|
||||
| protoclass.js:8:3:8:13 | this.method | protoclass.js:13:22:13:34 | function() {} |
|
||||
| protoclass.js:9:11:9:21 | this.method | protoclass.js:13:22:13:34 | function() {} |
|
||||
| protoclass.js:13:1:13:1 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} |
|
||||
| protoclass.js:13:1:13:18 | F.prototype.method | protoclass.js:13:22:13:34 | function() {} |
|
||||
| protoclass.js:13:1:13:34 | F.proto ... on() {} | protoclass.js:13:22:13:34 | function() {} |
|
||||
| protoclass.js:13:22:13:34 | function() {} | protoclass.js:13:22:13:34 | function() {} |
|
||||
| protoclass.js:15:16:15:16 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} |
|
||||
| reflection.js:1:1:3:1 | functio ... x+y;\\n} | reflection.js:1:1:3:1 | functio ... x+y;\\n} |
|
||||
| reflection.js:5:3:5:5 | add | reflection.js:1:1:3:1 | functio ... x+y;\\n} |
|
||||
| reflection.js:5:3:5:11 | add.apply | reflection.js:5:15:5:39 | functio ... n 56; } |
|
||||
| reflection.js:5:3:5:39 | add.app ... n 56; } | reflection.js:5:15:5:39 | functio ... n 56; } |
|
||||
| reflection.js:5:15:5:14 | this | reflection.js:1:1:3:1 | functio ... x+y;\\n} |
|
||||
| reflection.js:5:15:5:39 | functio ... n 56; } | reflection.js:5:15:5:39 | functio ... n 56; } |
|
||||
@@ -163,11 +167,13 @@ test_getAFunctionValue
|
||||
| tst.js:42:2:42:26 | functio ... rn x; } | tst.js:42:2:42:26 | functio ... rn x; } |
|
||||
| tst.js:44:1:44:15 | function A() {} | tst.js:44:1:44:15 | function A() {} |
|
||||
| tst.js:45:1:45:1 | A | tst.js:44:1:44:15 | function A() {} |
|
||||
| tst.js:45:1:45:13 | A.prototype.f | tst.js:45:17:47:1 | functio ... .g();\\n} |
|
||||
| tst.js:45:1:47:1 | A.proto ... .g();\\n} | tst.js:45:17:47:1 | functio ... .g();\\n} |
|
||||
| tst.js:45:17:47:1 | functio ... .g();\\n} | tst.js:45:17:47:1 | functio ... .g();\\n} |
|
||||
| tst.js:46:2:46:7 | this.g | tst.js:48:17:48:29 | function() {} |
|
||||
| tst.js:46:2:46:7 | this.g | tst.js:61:17:61:29 | function() {} |
|
||||
| tst.js:48:1:48:1 | A | tst.js:44:1:44:15 | function A() {} |
|
||||
| tst.js:48:1:48:13 | A.prototype.g | tst.js:48:17:48:29 | function() {} |
|
||||
| tst.js:48:1:48:29 | A.proto ... on() {} | tst.js:48:17:48:29 | function() {} |
|
||||
| tst.js:48:17:48:29 | function() {} | tst.js:48:17:48:29 | function() {} |
|
||||
| tst.js:50:1:50:15 | function B() {} | tst.js:50:1:50:15 | function B() {} |
|
||||
@@ -186,11 +192,13 @@ test_getAFunctionValue
|
||||
| tst.js:60:1:60:1 | C | tst.js:59:1:59:15 | function C() {} |
|
||||
| tst.js:60:19:60:19 | A | tst.js:44:1:44:15 | function A() {} |
|
||||
| tst.js:61:1:61:1 | C | tst.js:59:1:59:15 | function C() {} |
|
||||
| tst.js:61:1:61:13 | C.prototype.g | tst.js:61:17:61:29 | function() {} |
|
||||
| tst.js:61:1:61:29 | C.proto ... on() {} | tst.js:61:17:61:29 | function() {} |
|
||||
| tst.js:61:17:61:29 | function() {} | tst.js:61:17:61:29 | function() {} |
|
||||
| tst.js:63:1:67:2 | (functi ... f();\\n}) | tst.js:63:2:67:1 | functio ... .f();\\n} |
|
||||
| tst.js:63:2:67:1 | functio ... .f();\\n} | tst.js:63:2:67:1 | functio ... .f();\\n} |
|
||||
| tst.js:64:17:64:17 | B | tst.js:50:1:50:15 | function B() {} |
|
||||
| tst.js:65:5:65:7 | b.f | tst.js:65:11:65:23 | function() {} |
|
||||
| tst.js:65:5:65:23 | b.f = function() {} | tst.js:65:11:65:23 | function() {} |
|
||||
| tst.js:65:11:65:23 | function() {} | tst.js:65:11:65:23 | function() {} |
|
||||
| tst.js:66:5:66:7 | b.f | tst.js:52:5:54:2 | functio ... g();\\n\\t} |
|
||||
|
||||
@@ -12,6 +12,7 @@ test_ApiObject
|
||||
test_Connection
|
||||
| client.js:1:10:1:27 | exportedConnection |
|
||||
| tst.js:7:15:7:18 | conn |
|
||||
| tst.js:8:5:8:19 | this.connection |
|
||||
| tst.js:11:5:11:19 | this.connection |
|
||||
| tst.js:16:10:16:49 | api.cha ... ction() |
|
||||
| tst.js:19:7:19:21 | getConnection() |
|
||||
@@ -20,7 +21,9 @@ test_Connection
|
||||
| tst.js:48:7:48:21 | getConnection() |
|
||||
| tst.js:54:37:54:51 | getConnection() |
|
||||
| tst.js:57:14:57:48 | config. ... ction') |
|
||||
| tst.js:62:3:62:36 | MyAppli ... nection |
|
||||
| tst.js:62:40:62:79 | api.cha ... ction() |
|
||||
| tst.js:63:3:63:34 | MyAppli ... onflict |
|
||||
| tst.js:63:38:63:77 | api.cha ... ction() |
|
||||
| tst.js:67:14:67:47 | MyAppli ... nection |
|
||||
| tst.js:78:35:78:49 | getConnection() |
|
||||
@@ -41,6 +44,7 @@ test_Connection
|
||||
| tst.js:118:12:118:26 | getConnection() |
|
||||
| tst.js:120:21:120:24 | conn |
|
||||
| tst.js:126:22:126:25 | conn |
|
||||
| tst_conflict.js:6:3:6:34 | MyAppli ... onflict |
|
||||
| tst_conflict.js:6:38:6:77 | api.cha ... ction() |
|
||||
test_DataCallback
|
||||
| client.js:3:28:3:34 | x => {} |
|
||||
|
||||
@@ -11,6 +11,7 @@ apiObject
|
||||
| tst_conflict.js:6:38:6:58 | api.cha ... hain2() |
|
||||
connection
|
||||
| type tracker with call steps | tst.js:7:15:7:18 | conn |
|
||||
| type tracker with call steps | tst.js:8:5:8:19 | this.connection |
|
||||
| type tracker with call steps | tst.js:11:5:11:19 | this.connection |
|
||||
| type tracker with call steps | tst.js:80:16:80:19 | conn |
|
||||
| type tracker with call steps | tst.js:84:22:84:22 | x |
|
||||
@@ -30,7 +31,9 @@ connection
|
||||
| type tracker without call steps | tst.js:48:7:48:21 | getConnection() |
|
||||
| type tracker without call steps | tst.js:54:37:54:51 | getConnection() |
|
||||
| type tracker without call steps | tst.js:57:14:57:48 | config. ... ction') |
|
||||
| type tracker without call steps | tst.js:62:3:62:36 | MyAppli ... nection |
|
||||
| type tracker without call steps | tst.js:62:40:62:79 | api.cha ... ction() |
|
||||
| type tracker without call steps | tst.js:63:3:63:34 | MyAppli ... onflict |
|
||||
| type tracker without call steps | tst.js:63:38:63:77 | api.cha ... ction() |
|
||||
| type tracker without call steps | tst.js:67:14:67:47 | MyAppli ... nection |
|
||||
| type tracker without call steps | tst.js:78:35:78:49 | getConnection() |
|
||||
@@ -43,6 +46,7 @@ connection
|
||||
| type tracker without call steps | tst.js:118:12:118:26 | getConnection() |
|
||||
| type tracker without call steps | tst.js:120:21:120:24 | conn |
|
||||
| type tracker without call steps | tst.js:126:22:126:25 | conn |
|
||||
| type tracker without call steps | tst_conflict.js:6:3:6:34 | MyAppli ... onflict |
|
||||
| type tracker without call steps | tst_conflict.js:6:38:6:77 | api.cha ... ction() |
|
||||
| type tracker without call steps with property conflict | tst.js:63:3:63:25 | MyAppli ... mespace |
|
||||
| type tracker without call steps with property conflict | tst_conflict.js:6:3:6:25 | MyAppli ... mespace |
|
||||
|
||||
@@ -3227,10 +3227,13 @@ getRouteHandlerContainerStep
|
||||
| src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] |
|
||||
| src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b |
|
||||
dbUse
|
||||
| src/middleware-flow.js:6:5:6:10 | req.db |
|
||||
| src/middleware-flow.js:6:5:6:21 | req.db = new DB() |
|
||||
| src/middleware-flow.js:6:14:6:21 | new DB() |
|
||||
| src/middleware-flow.js:7:5:7:15 | req.deep.db |
|
||||
| src/middleware-flow.js:7:5:7:26 | req.dee ... ew DB() |
|
||||
| src/middleware-flow.js:7:19:7:26 | new DB() |
|
||||
| src/middleware-flow.js:8:5:8:22 | req.deep.access.db |
|
||||
| src/middleware-flow.js:8:5:8:33 | req.dee ... ew DB() |
|
||||
| src/middleware-flow.js:8:26:8:33 | new DB() |
|
||||
| src/middleware-flow.js:18:9:18:14 | req.db |
|
||||
|
||||
@@ -159,6 +159,11 @@ nodes
|
||||
| xss-through-dom.js:141:25:141:27 | src |
|
||||
| xss-through-dom.js:150:24:150:26 | src |
|
||||
| xss-through-dom.js:150:24:150:26 | src |
|
||||
| xss-through-dom.js:154:25:154:27 | msg |
|
||||
| xss-through-dom.js:155:27:155:29 | msg |
|
||||
| xss-through-dom.js:155:27:155:29 | msg |
|
||||
| xss-through-dom.js:159:34:159:52 | $("textarea").val() |
|
||||
| xss-through-dom.js:159:34:159:52 | $("textarea").val() |
|
||||
edges
|
||||
| forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values |
|
||||
| forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values |
|
||||
@@ -263,6 +268,10 @@ edges
|
||||
| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:150:24:150:26 | src |
|
||||
| xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:139:11:139:52 | src |
|
||||
| xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:139:11:139:52 | src |
|
||||
| xss-through-dom.js:154:25:154:27 | msg | xss-through-dom.js:155:27:155:29 | msg |
|
||||
| xss-through-dom.js:154:25:154:27 | msg | xss-through-dom.js:155:27:155:29 | msg |
|
||||
| xss-through-dom.js:159:34:159:52 | $("textarea").val() | xss-through-dom.js:154:25:154:27 | msg |
|
||||
| xss-through-dom.js:159:34:159:52 | $("textarea").val() | xss-through-dom.js:154:25:154:27 | msg |
|
||||
#select
|
||||
| forms.js:9:31:9:40 | values.foo | forms.js:8:23:8:28 | values | forms.js:9:31:9:40 | values.foo | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:8:23:8:28 | values | DOM text |
|
||||
| forms.js:12:31:12:40 | values.bar | forms.js:11:24:11:29 | values | forms.js:12:31:12:40 | values.bar | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:11:24:11:29 | values | DOM text |
|
||||
@@ -307,3 +316,4 @@ edges
|
||||
| xss-through-dom.js:140:19:140:21 | src | xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:140:19:140:21 | src | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:139:17:139:52 | documen ... k").src | DOM text |
|
||||
| xss-through-dom.js:141:25:141:27 | src | xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:141:25:141:27 | src | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:139:17:139:52 | documen ... k").src | DOM text |
|
||||
| xss-through-dom.js:150:24:150:26 | src | xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:150:24:150:26 | src | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:139:17:139:52 | documen ... k").src | DOM text |
|
||||
| xss-through-dom.js:155:27:155:29 | msg | xss-through-dom.js:159:34:159:52 | $("textarea").val() | xss-through-dom.js:155:27:155:29 | msg | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:159:34:159:52 | $("textarea").val() | DOM text |
|
||||
|
||||
@@ -148,4 +148,15 @@ const cashDom = require("cash-dom");
|
||||
cashDom("#id").html(DOMPurify ? DOMPurify.sanitize(src) : src); // OK
|
||||
|
||||
$("<a />", { html: src }).appendTo("#id"); // NOT OK
|
||||
|
||||
function foo() {
|
||||
window.VeryUniqueXssTestName = {
|
||||
send: function (msg) {
|
||||
$("#id").html(msg); // NOT OK
|
||||
},
|
||||
};
|
||||
|
||||
VeryUniqueXssTestName.send($("textarea").val());
|
||||
}
|
||||
foo()
|
||||
})();
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed some accidental predicate visibility in the backwards-compatible wrapper for data flow configurations. In particular `DataFlow::hasFlowPath`, `DataFlow::hasFlow`, `DataFlow::hasFlowTo`, and `DataFlow::hasFlowToExpr` were accidentally exposed in a single version.
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -11,16 +11,57 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import IsComparisons
|
||||
|
||||
from Compare comp, Cmpop op, ClassValue c, string alt
|
||||
where
|
||||
invalid_portable_is_comparison(comp, op, c) and
|
||||
not cpython_interned_constant(comp.getASubExpression()) and
|
||||
(
|
||||
op instanceof Is and alt = "=="
|
||||
/** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */
|
||||
predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) {
|
||||
exists(CompareNode fcomp | fcomp = comp.getAFlowNode() |
|
||||
fcomp.operands(left, op, right) and
|
||||
(op instanceof Is or op instanceof IsNot)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate cpython_interned_value(Expr e) {
|
||||
exists(string text | text = e.(StrConst).getText() |
|
||||
text.length() = 0
|
||||
or
|
||||
op instanceof IsNot and alt = "!="
|
||||
text.length() = 1 and text.regexpMatch("[U+0000-U+00ff]")
|
||||
)
|
||||
or
|
||||
exists(int i | i = e.(IntegerLiteral).getN().toInt() | -5 <= i and i <= 256)
|
||||
or
|
||||
exists(Tuple t | t = e and not exists(t.getAnElt()))
|
||||
}
|
||||
|
||||
predicate uninterned_literal(Expr e) {
|
||||
(
|
||||
e instanceof StrConst
|
||||
or
|
||||
e instanceof IntegerLiteral
|
||||
or
|
||||
e instanceof FloatLiteral
|
||||
or
|
||||
e instanceof Dict
|
||||
or
|
||||
e instanceof List
|
||||
or
|
||||
e instanceof Tuple
|
||||
) and
|
||||
not cpython_interned_value(e)
|
||||
}
|
||||
|
||||
from Compare comp, Cmpop op, string alt
|
||||
where
|
||||
exists(ControlFlowNode left, ControlFlowNode right |
|
||||
comparison_using_is(comp, left, op, right) and
|
||||
(
|
||||
op instanceof Is and alt = "=="
|
||||
or
|
||||
op instanceof IsNot and alt = "!="
|
||||
)
|
||||
|
|
||||
uninterned_literal(left.getNode())
|
||||
or
|
||||
uninterned_literal(right.getNode())
|
||||
)
|
||||
select comp,
|
||||
"Values compared using '" + op.getSymbol() +
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed some accidental predicate visibility in the backwards-compatible wrapper for data flow configurations. In particular `DataFlow::hasFlowPath`, `DataFlow::hasFlow`, `DataFlow::hasFlowTo`, and `DataFlow::hasFlowToExpr` were accidentally exposed in a single version.
|
||||
@@ -43,11 +43,16 @@ class MethodCallSynth extends MethodCallImpl, TMethodCallSynth {
|
||||
|
||||
final override AstNode getReceiverImpl() { synthChild(this, 0, result) }
|
||||
|
||||
final override AstNode getArgumentImpl(int n) { synthChild(this, n + 1, result) and n >= 0 }
|
||||
final override AstNode getArgumentImpl(int n) {
|
||||
synthChild(this, n + 1, result) and
|
||||
n in [0 .. this.getNumberOfArgumentsImpl() - 1]
|
||||
}
|
||||
|
||||
final override int getNumberOfArgumentsImpl() { this = TMethodCallSynth(_, _, _, _, result) }
|
||||
|
||||
final override Block getBlockImpl() { synthChild(this, -2, result) }
|
||||
final override Block getBlockImpl() {
|
||||
synthChild(this, this.getNumberOfArgumentsImpl() + 1, result)
|
||||
}
|
||||
}
|
||||
|
||||
class IdentifierMethodCall extends MethodCallImpl, TIdentifierMethodCall {
|
||||
|
||||
@@ -21,6 +21,8 @@ private module Cached {
|
||||
qName = getAnAssumedGlobalConst()
|
||||
or
|
||||
qName = namespaceDeclaration(_)
|
||||
or
|
||||
qName = getAnAssumedGlobalNamespacePrefix(_)
|
||||
} or
|
||||
TUnresolved(Namespace n) { not exists(namespaceDeclaration(n)) }
|
||||
|
||||
@@ -36,6 +38,8 @@ private module Cached {
|
||||
TResolved(container) = resolveConstantReadAccess(n.getScopeExpr()) and
|
||||
result = scopeAppend(container, n.getName())
|
||||
)
|
||||
or
|
||||
result = getAnAssumedGlobalNamespacePrefix(n)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -407,12 +411,35 @@ private module ResolveImpl {
|
||||
*/
|
||||
string getAnAssumedGlobalConst() {
|
||||
exists(ConstantAccess access |
|
||||
not exists(access.getScopeExpr()) and
|
||||
result = access.getName() and
|
||||
isToplevel(access)
|
||||
)
|
||||
}
|
||||
|
||||
private ConstantAccess getANamespaceScopeInTopLevel() {
|
||||
result.(Namespace).getEnclosingModule() instanceof Toplevel
|
||||
or
|
||||
result = getANamespaceScopeInTopLevel().getScopeExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the syntactical qualified name of the given constant access, which must be a top-level
|
||||
* namespace or scope prefix thereof.
|
||||
*
|
||||
* For example, for `module A::B::C` this gets `A`, `A::B`, and `A::B::C` for the two prefixes
|
||||
* and the module itself, respectively.
|
||||
*/
|
||||
string getAnAssumedGlobalNamespacePrefix(ConstantAccess access) {
|
||||
access = getANamespaceScopeInTopLevel() and
|
||||
(
|
||||
not exists(access.getScopeExpr()) and
|
||||
result = access.getName()
|
||||
or
|
||||
result =
|
||||
scopeAppend(getAnAssumedGlobalNamespacePrefix(access.getScopeExpr()), access.getName())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string isDefinedConstantNonRec(string container, string name) {
|
||||
result = resolveConstantWriteAccessNonRec(_, container, name)
|
||||
@@ -420,6 +447,12 @@ private module ResolveImpl {
|
||||
result = [builtin(), getAnAssumedGlobalConst()] and
|
||||
name = result and
|
||||
container = "Object"
|
||||
or
|
||||
exists(ConstantAccess access |
|
||||
container = getAnAssumedGlobalNamespacePrefix(access.getScopeExpr()) and
|
||||
name = access.getName() and
|
||||
result = getAnAssumedGlobalNamespacePrefix(access)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -818,7 +818,7 @@ private module AssignOperationDesugar {
|
||||
i in [0 .. sao.getNumberOfArguments()]
|
||||
or
|
||||
parent = setter and
|
||||
i = opAssignIndex + 1 and
|
||||
i = opAssignIndex and
|
||||
child =
|
||||
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sao, opAssignIndex)))
|
||||
)
|
||||
@@ -975,7 +975,7 @@ private module DestructuredAssignDesugar {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate destructuredAssignSynthesis(AstNode parent, int i, Child child) {
|
||||
exists(DestructuredAssignExpr tae |
|
||||
exists(DestructuredAssignExpr tae, int total | total = tae.getNumberOfElements() |
|
||||
parent = tae and
|
||||
i = -1 and
|
||||
child = SynthChild(StmtSequenceKind())
|
||||
@@ -998,15 +998,13 @@ private module DestructuredAssignDesugar {
|
||||
)
|
||||
or
|
||||
parent = seq and
|
||||
i = tae.getNumberOfElements() and
|
||||
i = total and
|
||||
child = SynthChild(AssignExprKind())
|
||||
or
|
||||
exists(AstNode assign | assign = TAssignExprSynth(seq, tae.getNumberOfElements()) |
|
||||
exists(AstNode assign | assign = TAssignExprSynth(seq, total) |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
child =
|
||||
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae,
|
||||
tae.getNumberOfElements())))
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae, total)))
|
||||
or
|
||||
parent = assign and
|
||||
i = 1 and
|
||||
@@ -1022,12 +1020,10 @@ private module DestructuredAssignDesugar {
|
||||
restIndex = tae.getRestIndexOrNumberOfElements()
|
||||
|
|
||||
parent = seq and
|
||||
i = j + 1 + tae.getNumberOfElements() and
|
||||
i = j + 1 + total and
|
||||
child = SynthChild(AssignExprKind())
|
||||
or
|
||||
exists(AstNode assign |
|
||||
assign = TAssignExprSynth(seq, j + 1 + tae.getNumberOfElements())
|
||||
|
|
||||
exists(AstNode assign | assign = TAssignExprSynth(seq, j + 1 + total) |
|
||||
exists(LhsWithReceiver mc | mc = elem |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
@@ -1063,9 +1059,7 @@ private module DestructuredAssignDesugar {
|
||||
or
|
||||
parent = TMethodCallSynth(assign, 1, _, _, _) and
|
||||
i = 0 and
|
||||
child =
|
||||
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae,
|
||||
tae.getNumberOfElements())))
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae, total)))
|
||||
or
|
||||
j < restIndex and
|
||||
parent = TMethodCallSynth(assign, 1, _, _, _) and
|
||||
@@ -1086,14 +1080,14 @@ private module DestructuredAssignDesugar {
|
||||
child = SynthChild(IntegerLiteralKind(j))
|
||||
or
|
||||
i = 1 and
|
||||
child = SynthChild(IntegerLiteralKind(restIndex - tae.getNumberOfElements()))
|
||||
child = SynthChild(IntegerLiteralKind(restIndex - total))
|
||||
)
|
||||
)
|
||||
or
|
||||
j > restIndex and
|
||||
parent = TMethodCallSynth(assign, 1, _, _, _) and
|
||||
i = 1 and
|
||||
child = SynthChild(IntegerLiteralKind(j - tae.getNumberOfElements()))
|
||||
child = SynthChild(IntegerLiteralKind(j - total))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1284,10 +1278,10 @@ private module ForLoopDesugar {
|
||||
child = childRef(for.getValue()) // value is the Enumerable
|
||||
or
|
||||
parent = eachCall and
|
||||
i = -2 and
|
||||
i = 1 and
|
||||
child = SynthChild(BraceBlockKind())
|
||||
or
|
||||
exists(Block block | block = TBraceBlockSynth(eachCall, -2) |
|
||||
exists(Block block | block = TBraceBlockSynth(eachCall, 1) |
|
||||
// block params
|
||||
parent = block and
|
||||
i = 0 and
|
||||
@@ -1534,14 +1528,13 @@ private module SafeNavigationCallDesugar {
|
||||
i = 1
|
||||
)
|
||||
or
|
||||
parent = TMethodCallSynth(ifExpr, 2, _, _, _) and
|
||||
(
|
||||
exists(int arity | parent = TMethodCallSynth(ifExpr, 2, _, _, arity) |
|
||||
i = 0 and
|
||||
child = SynthChild(local)
|
||||
or
|
||||
child = childRef(call.getArgumentImpl(i - 1))
|
||||
or
|
||||
child = childRef(call.getBlockImpl()) and i = -2
|
||||
child = childRef(call.getBlockImpl()) and i = arity + 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -36,8 +36,6 @@ private predicate shouldPrintAstEdge(AstNode parent, string edgeName, AstNode ch
|
||||
any(PrintAstConfiguration config).shouldPrintAstEdge(parent, edgeName, child)
|
||||
}
|
||||
|
||||
private int nonSynthIndex() { result = min([-1, any(int i | exists(getSynthChild(_, i)))]) - 1 }
|
||||
|
||||
newtype TPrintNode =
|
||||
TPrintRegularAstNode(AstNode n) { shouldPrintNode(n) } or
|
||||
TPrintRegExpNode(RE::RegExpTerm term) {
|
||||
@@ -115,10 +113,23 @@ class PrintRegularAstNode extends PrintAstNode, TPrintRegularAstNode {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate parentIsSynthesized() {
|
||||
exists(AstNode parent |
|
||||
shouldPrintAstEdge(parent, _, astNode) and
|
||||
parent.isSynthesized()
|
||||
)
|
||||
}
|
||||
|
||||
private int getSynthAstNodeIndex() {
|
||||
not astNode.isSynthesized() and result = nonSynthIndex()
|
||||
this.parentIsSynthesized() and
|
||||
exists(AstNode parent |
|
||||
shouldPrintAstEdge(parent, _, astNode) and
|
||||
parent.isSynthesized() and
|
||||
synthChild(parent, result, astNode)
|
||||
)
|
||||
or
|
||||
astNode = getSynthChild(astNode.getParent(), result)
|
||||
not this.parentIsSynthesized() and
|
||||
result = 0
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
@@ -129,8 +140,8 @@ class PrintRegularAstNode extends PrintAstNode, TPrintRegularAstNode {
|
||||
|
|
||||
p
|
||||
order by
|
||||
f.getBaseName(), f.getAbsolutePath(), l.getStartLine(), l.getStartColumn(),
|
||||
l.getEndLine(), l.getEndColumn(), p.getSynthAstNodeIndex()
|
||||
f.getBaseName(), f.getAbsolutePath(), l.getStartLine(), p.getSynthAstNodeIndex(),
|
||||
l.getStartColumn(), l.getEndLine(), l.getEndColumn()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `rb/sensitive-get-query` no longer reports flow paths from input parameters to sensitive use nodes. This avoids cases where many flow paths could be generated for a single parameter, which caused excessive paths to be generated.
|
||||
@@ -2,7 +2,7 @@
|
||||
* @name Sensitive data read from GET request
|
||||
* @description Placing sensitive data in a GET request increases the risk of
|
||||
* the data being exposed to an attacker.
|
||||
* @kind path-problem
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 6.5
|
||||
* @precision high
|
||||
@@ -12,12 +12,10 @@
|
||||
*/
|
||||
|
||||
import ruby
|
||||
import DataFlow::PathGraph
|
||||
import codeql.ruby.security.SensitiveGetQueryQuery
|
||||
import codeql.ruby.security.SensitiveActions
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveGetQuery::Configuration config
|
||||
where config.hasFlowPath(source, sink)
|
||||
select source.getNode(), source, sink,
|
||||
"$@ for GET requests uses query parameter as sensitive data.",
|
||||
source.getNode().(SensitiveGetQuery::Source).getHandler(), "Route handler"
|
||||
from DataFlow::Node source, DataFlow::Node sink, SensitiveGetQuery::Configuration config
|
||||
where config.hasFlow(source, sink)
|
||||
select source, "$@ for GET requests uses query parameter as sensitive data.",
|
||||
source.(SensitiveGetQuery::Source).getHandler(), "Route handler"
|
||||
|
||||
@@ -25,28 +25,28 @@ calls/calls.rb:
|
||||
# 67| getReceiver: [ConstantReadAccess] X
|
||||
# 226| [ForExpr] for ... in ...
|
||||
# 226| getDesugared: [MethodCall] call to each
|
||||
# 226| getReceiver: [MethodCall] call to bar
|
||||
# 226| getReceiver: [SelfVariableAccess] self
|
||||
# 226| getBlock: [BraceBlock] { ... }
|
||||
# 226| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 226| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
# 226| getStmt: [AssignExpr] ... = ...
|
||||
# 226| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 226| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 226| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 227| getStmt: [MethodCall] call to baz
|
||||
# 227| getReceiver: [SelfVariableAccess] self
|
||||
# 226| getReceiver: [MethodCall] call to bar
|
||||
# 226| getReceiver: [SelfVariableAccess] self
|
||||
# 229| [ForExpr] for ... in ...
|
||||
# 229| getDesugared: [MethodCall] call to each
|
||||
# 229| getReceiver: [MethodCall] call to bar
|
||||
# 229| getReceiver: [ConstantReadAccess] X
|
||||
# 229| getBlock: [BraceBlock] { ... }
|
||||
# 229| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 229| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
# 229| getStmt: [AssignExpr] ... = ...
|
||||
# 229| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 229| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 229| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 230| getStmt: [MethodCall] call to baz
|
||||
# 230| getReceiver: [ConstantReadAccess] X
|
||||
# 229| getReceiver: [MethodCall] call to bar
|
||||
# 229| getReceiver: [ConstantReadAccess] X
|
||||
# 249| [HashLiteral] {...}
|
||||
# 249| getDesugared: [MethodCall] call to []
|
||||
# 249| getReceiver: [ConstantReadAccess] Hash
|
||||
@@ -65,8 +65,8 @@ calls/calls.rb:
|
||||
# 316| getStmt: [SetterMethodCall] call to foo=
|
||||
# 316| getReceiver: [SelfVariableAccess] self
|
||||
# 316| getArgument: [AssignExpr] ... = ...
|
||||
# 316| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
# 316| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 316| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
# 316| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 317| [AssignExpr] ... = ...
|
||||
# 317| getDesugared: [StmtSequence] ...
|
||||
@@ -75,14 +75,31 @@ calls/calls.rb:
|
||||
# 317| getReceiver: [SelfVariableAccess] self
|
||||
# 317| getArgument: [IntegerLiteral] 0
|
||||
# 317| getArgument: [AssignExpr] ... = ...
|
||||
# 317| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
# 317| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 317| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
# 317| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 318| [AssignExpr] ... = ...
|
||||
# 318| getDesugared: [StmtSequence] ...
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 318| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 318| getReceiver: [SelfVariableAccess] self
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 318| getAnOperand/getRightOperand: [SplatExpr] * ...
|
||||
# 318| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...]
|
||||
# 318| getDesugared: [MethodCall] call to []
|
||||
# 318| getReceiver: [ConstantReadAccess] Array
|
||||
# 318| getArgument: [IntegerLiteral] 1
|
||||
# 318| getArgument: [IntegerLiteral] 2
|
||||
# 318| getArgument: [IntegerLiteral] 3
|
||||
# 318| getArgument: [IntegerLiteral] 4
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getDesugared: [StmtSequence] ...
|
||||
# 318| getStmt: [SetterMethodCall] call to foo=
|
||||
@@ -95,9 +112,6 @@ calls/calls.rb:
|
||||
# 318| getStmt: [LocalVariableAccess] __synth__0__1
|
||||
# 318| getAnOperand/getLeftOperand: [MethodCall] call to foo
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getDesugared: [StmtSequence] ...
|
||||
# 318| getStmt: [SetterMethodCall] call to bar=
|
||||
# 318| getReceiver: [LocalVariableAccess] __synth__1
|
||||
@@ -111,56 +125,23 @@ calls/calls.rb:
|
||||
# 318| getStmt: [LocalVariableAccess] __synth__0__1
|
||||
# 318| getAnOperand/getLeftOperand: [MethodCall] call to bar
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 318| getReceiver: [SelfVariableAccess] self
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getDesugared: [StmtSequence] ...
|
||||
# 318| getStmt: [SetterMethodCall] call to []=
|
||||
# 318| getReceiver: [LocalVariableAccess] __synth__2
|
||||
# 318| getArgument: [IntegerLiteral] 4
|
||||
# 318| getArgument: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 318| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 318| getReceiver: [LocalVariableAccess] __synth__3
|
||||
# 318| getArgument: [IntegerLiteral] -1
|
||||
# 318| getArgument: [IntegerLiteral] 4
|
||||
# 318| getStmt: [LocalVariableAccess] __synth__0__1
|
||||
# 318| getAnOperand/getLeftOperand: [MethodCall] call to []
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 318| getAnOperand/getRightOperand: [SplatExpr] * ...
|
||||
# 318| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...]
|
||||
# 318| getDesugared: [MethodCall] call to []
|
||||
# 318| getReceiver: [ConstantReadAccess] Array
|
||||
# 318| getArgument: [IntegerLiteral] 1
|
||||
# 318| getArgument: [IntegerLiteral] 2
|
||||
# 318| getArgument: [IntegerLiteral] 3
|
||||
# 318| getArgument: [IntegerLiteral] 4
|
||||
# 319| [AssignExpr] ... = ...
|
||||
# 319| getDesugared: [StmtSequence] ...
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] a
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__2
|
||||
# 319| getArgument: [IntegerLiteral] 0
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 319| getReceiver: [SelfVariableAccess] self
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getDesugared: [StmtSequence] ...
|
||||
# 319| getStmt: [SetterMethodCall] call to []=
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__1
|
||||
# 319| getArgument: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__2
|
||||
# 319| getArgument: [RangeLiteral] _ .. _
|
||||
# 319| getBegin: [IntegerLiteral] 1
|
||||
# 319| getEnd: [IntegerLiteral] -1
|
||||
# 319| getArgument: [IntegerLiteral] 5
|
||||
# 319| getStmt: [LocalVariableAccess] __synth__0__1
|
||||
# 319| getAnOperand/getLeftOperand: [MethodCall] call to []
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 319| getAnOperand/getRightOperand: [SplatExpr] * ...
|
||||
@@ -170,34 +151,49 @@ calls/calls.rb:
|
||||
# 319| getArgument: [IntegerLiteral] 1
|
||||
# 319| getArgument: [IntegerLiteral] 2
|
||||
# 319| getArgument: [IntegerLiteral] 3
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] a
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__2
|
||||
# 319| getArgument: [IntegerLiteral] 0
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getDesugared: [StmtSequence] ...
|
||||
# 319| getStmt: [SetterMethodCall] call to []=
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__1
|
||||
# 319| getArgument: [IntegerLiteral] 5
|
||||
# 319| getArgument: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__2
|
||||
# 319| getArgument: [RangeLiteral] _ .. _
|
||||
# 319| getBegin: [IntegerLiteral] 1
|
||||
# 319| getEnd: [IntegerLiteral] -1
|
||||
# 319| getStmt: [LocalVariableAccess] __synth__0__1
|
||||
# 319| getAnOperand/getLeftOperand: [MethodCall] call to []
|
||||
# 320| [AssignAddExpr] ... += ...
|
||||
# 320| getDesugared: [StmtSequence] ...
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 320| getStmt: [SetterMethodCall] call to count=
|
||||
# 320| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 320| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 320| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 320| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 320| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to count
|
||||
# 320| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 320| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
|
||||
# 320| getStmt: [SetterMethodCall] call to count=
|
||||
# 320| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 320| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 320| getStmt: [LocalVariableAccess] __synth__1
|
||||
# 321| [AssignAddExpr] ... += ...
|
||||
# 321| getDesugared: [StmtSequence] ...
|
||||
# 321| getStmt: [AssignExpr] ... = ...
|
||||
# 321| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 321| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 321| getReceiver: [SelfVariableAccess] self
|
||||
# 321| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 321| getStmt: [SetterMethodCall] call to []=
|
||||
# 321| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 321| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 321| getArgument: [LocalVariableAccess] __synth__2
|
||||
# 321| getStmt: [AssignExpr] ... = ...
|
||||
# 321| getAnOperand/getRightOperand: [IntegerLiteral] 0
|
||||
# 321| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 321| getAnOperand/getRightOperand: [IntegerLiteral] 0
|
||||
# 321| getStmt: [AssignExpr] ... = ...
|
||||
# 321| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 321| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
@@ -205,35 +201,33 @@ calls/calls.rb:
|
||||
# 321| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 321| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 321| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
|
||||
# 321| getStmt: [SetterMethodCall] call to []=
|
||||
# 321| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 321| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 321| getArgument: [LocalVariableAccess] __synth__2
|
||||
# 321| getStmt: [LocalVariableAccess] __synth__2
|
||||
# 322| [AssignMulExpr] ... *= ...
|
||||
# 322| getDesugared: [StmtSequence] ...
|
||||
# 322| getStmt: [AssignExpr] ... = ...
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 322| getAnOperand/getRightOperand: [MethodCall] call to bar
|
||||
# 322| getReceiver: [MethodCall] call to foo
|
||||
# 322| getReceiver: [SelfVariableAccess] self
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 322| getStmt: [SetterMethodCall] call to []=
|
||||
# 322| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__2
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__3
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__4
|
||||
# 322| getStmt: [AssignExpr] ... = ...
|
||||
# 322| getAnOperand/getRightOperand: [IntegerLiteral] 0
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 322| getAnOperand/getRightOperand: [IntegerLiteral] 0
|
||||
# 322| getStmt: [AssignExpr] ... = ...
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 322| getAnOperand/getRightOperand: [MethodCall] call to baz
|
||||
# 322| getReceiver: [MethodCall] call to foo
|
||||
# 322| getReceiver: [SelfVariableAccess] self
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 322| getStmt: [AssignExpr] ... = ...
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 322| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 322| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo
|
||||
# 322| getReceiver: [MethodCall] call to foo
|
||||
# 322| getReceiver: [SelfVariableAccess] self
|
||||
# 322| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 322| getStmt: [AssignExpr] ... = ...
|
||||
# 322| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__4
|
||||
# 322| getAnOperand/getRightOperand: [MulExpr] ... * ...
|
||||
@@ -243,9 +237,30 @@ calls/calls.rb:
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__2
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__3
|
||||
# 322| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 2
|
||||
# 322| getStmt: [SetterMethodCall] call to []=
|
||||
# 322| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__2
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__3
|
||||
# 322| getArgument: [LocalVariableAccess] __synth__4
|
||||
# 322| getStmt: [LocalVariableAccess] __synth__4
|
||||
# 342| [ForExpr] for ... in ...
|
||||
# 342| getDesugared: [MethodCall] call to each
|
||||
# 342| getReceiver: [ArrayLiteral] [...]
|
||||
# 342| getDesugared: [MethodCall] call to []
|
||||
# 342| getReceiver: [ConstantReadAccess] Array
|
||||
# 342| getArgument: [ArrayLiteral] [...]
|
||||
# 342| getDesugared: [MethodCall] call to []
|
||||
# 342| getReceiver: [ConstantReadAccess] Array
|
||||
# 342| getArgument: [IntegerLiteral] 1
|
||||
# 342| getArgument: [IntegerLiteral] 2
|
||||
# 342| getArgument: [IntegerLiteral] 3
|
||||
# 342| getArgument: [ArrayLiteral] [...]
|
||||
# 342| getDesugared: [MethodCall] call to []
|
||||
# 342| getReceiver: [ConstantReadAccess] Array
|
||||
# 342| getArgument: [IntegerLiteral] 4
|
||||
# 342| getArgument: [IntegerLiteral] 5
|
||||
# 342| getArgument: [IntegerLiteral] 6
|
||||
# 342| getBlock: [BraceBlock] { ... }
|
||||
# 342| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 342| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
@@ -276,41 +291,29 @@ calls/calls.rb:
|
||||
# 343| getArgument: [LocalVariableAccess] x
|
||||
# 343| getArgument: [LocalVariableAccess] y
|
||||
# 343| getArgument: [LocalVariableAccess] z
|
||||
# 342| getReceiver: [ArrayLiteral] [...]
|
||||
# 342| getDesugared: [MethodCall] call to []
|
||||
# 342| getReceiver: [ConstantReadAccess] Array
|
||||
# 342| getArgument: [ArrayLiteral] [...]
|
||||
# 342| getDesugared: [MethodCall] call to []
|
||||
# 342| getReceiver: [ConstantReadAccess] Array
|
||||
# 342| getArgument: [IntegerLiteral] 1
|
||||
# 342| getArgument: [IntegerLiteral] 2
|
||||
# 342| getArgument: [IntegerLiteral] 3
|
||||
# 342| getArgument: [ArrayLiteral] [...]
|
||||
# 342| getDesugared: [MethodCall] call to []
|
||||
# 342| getReceiver: [ConstantReadAccess] Array
|
||||
# 342| getArgument: [IntegerLiteral] 4
|
||||
# 342| getArgument: [IntegerLiteral] 5
|
||||
# 342| getArgument: [IntegerLiteral] 6
|
||||
# 364| [MethodCall] call to empty?
|
||||
# 364| getDesugared: [StmtSequence] ...
|
||||
# 364| getStmt: [AssignExpr] ... = ...
|
||||
# 364| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 364| getAnOperand/getRightOperand: [MethodCall] call to list
|
||||
# 364| getReceiver: [SelfVariableAccess] self
|
||||
# 364| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 364| getStmt: [IfExpr] if ...
|
||||
# 364| getCondition: [MethodCall] call to ==
|
||||
# 364| getReceiver: [NilLiteral] nil
|
||||
# 364| getArgument: [LocalVariableAccess] __synth__0__1
|
||||
# 364| getBranch/getThen: [NilLiteral] nil
|
||||
# 364| getBranch/getElse: [MethodCall] call to empty?
|
||||
# 364| getReceiver: [LocalVariableAccess] __synth__0__1
|
||||
# 364| getCondition: [MethodCall] call to ==
|
||||
# 364| getArgument: [LocalVariableAccess] __synth__0__1
|
||||
# 364| getReceiver: [NilLiteral] nil
|
||||
# 366| [MethodCall] call to bar
|
||||
# 366| getDesugared: [StmtSequence] ...
|
||||
# 366| getStmt: [AssignExpr] ... = ...
|
||||
# 366| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 366| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 366| getReceiver: [SelfVariableAccess] self
|
||||
# 366| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 366| getStmt: [IfExpr] if ...
|
||||
# 366| getCondition: [MethodCall] call to ==
|
||||
# 366| getReceiver: [NilLiteral] nil
|
||||
# 366| getArgument: [LocalVariableAccess] __synth__0__1
|
||||
# 366| getBranch/getThen: [NilLiteral] nil
|
||||
# 366| getBranch/getElse: [MethodCall] call to bar
|
||||
# 366| getReceiver: [LocalVariableAccess] __synth__0__1
|
||||
@@ -320,9 +323,6 @@ calls/calls.rb:
|
||||
# 366| getParameter: [SimpleParameter] x
|
||||
# 366| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 366| getStmt: [LocalVariableAccess] x
|
||||
# 366| getCondition: [MethodCall] call to ==
|
||||
# 366| getArgument: [LocalVariableAccess] __synth__0__1
|
||||
# 366| getReceiver: [NilLiteral] nil
|
||||
control/cases.rb:
|
||||
# 90| [ArrayLiteral] %w(...)
|
||||
# 90| getDesugared: [MethodCall] call to []
|
||||
@@ -343,10 +343,10 @@ control/cases.rb:
|
||||
# 160| getValue: [MethodCall] call to expr
|
||||
# 160| getReceiver: [SelfVariableAccess] self
|
||||
# 160| getBranch: [InClause] in ... then ...
|
||||
# 160| getBody: [BooleanLiteral] true
|
||||
# 160| getPattern: [ArrayPattern] [ ..., * ]
|
||||
# 160| getPrefixElement: [IntegerLiteral] 1
|
||||
# 160| getPrefixElement: [IntegerLiteral] 2
|
||||
# 160| getBody: [BooleanLiteral] true
|
||||
# 160| getBranch/getElseBranch: [StmtSequence] else ...
|
||||
# 160| getStmt: [BooleanLiteral] false
|
||||
# 162| [MatchPattern] ... => ...
|
||||
@@ -354,7 +354,6 @@ control/cases.rb:
|
||||
# 162| getValue: [MethodCall] call to expr
|
||||
# 162| getReceiver: [SelfVariableAccess] self
|
||||
# 162| getBranch: [InClause] in ... then ...
|
||||
# 162| getBody: [NilLiteral] nil
|
||||
# 162| getPattern: [HashPattern] { ..., ** }
|
||||
# 162| getKey: [SymbolLiteral] :x
|
||||
# 162| getComponent: [StringTextComponent] x
|
||||
@@ -362,6 +361,7 @@ control/cases.rb:
|
||||
# 162| getKey: [SymbolLiteral] :y
|
||||
# 162| getComponent: [StringTextComponent] y
|
||||
# 162| getValue: [IntegerLiteral] 1
|
||||
# 162| getBody: [NilLiteral] nil
|
||||
constants/constants.rb:
|
||||
# 20| [ArrayLiteral] [...]
|
||||
# 20| getDesugared: [MethodCall] call to []
|
||||
@@ -595,12 +595,15 @@ literals/literals.rb:
|
||||
control/loops.rb:
|
||||
# 9| [ForExpr] for ... in ...
|
||||
# 9| getDesugared: [MethodCall] call to each
|
||||
# 9| getReceiver: [RangeLiteral] _ .. _
|
||||
# 9| getBegin: [IntegerLiteral] 1
|
||||
# 9| getEnd: [IntegerLiteral] 10
|
||||
# 9| getBlock: [BraceBlock] { ... }
|
||||
# 9| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 9| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
# 9| getStmt: [AssignExpr] ... = ...
|
||||
# 9| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 9| getAnOperand/getLeftOperand: [LocalVariableAccess] n
|
||||
# 9| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 10| getStmt: [AssignAddExpr] ... += ...
|
||||
# 10| getDesugared: [AssignExpr] ... = ...
|
||||
# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
|
||||
@@ -610,17 +613,17 @@ control/loops.rb:
|
||||
# 11| getStmt: [AssignExpr] ... = ...
|
||||
# 11| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
|
||||
# 11| getAnOperand/getRightOperand: [LocalVariableAccess] n
|
||||
# 9| getReceiver: [RangeLiteral] _ .. _
|
||||
# 9| getBegin: [IntegerLiteral] 1
|
||||
# 9| getEnd: [IntegerLiteral] 10
|
||||
# 16| [ForExpr] for ... in ...
|
||||
# 16| getDesugared: [MethodCall] call to each
|
||||
# 16| getReceiver: [RangeLiteral] _ .. _
|
||||
# 16| getBegin: [IntegerLiteral] 1
|
||||
# 16| getEnd: [IntegerLiteral] 10
|
||||
# 16| getBlock: [BraceBlock] { ... }
|
||||
# 16| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 16| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
# 16| getStmt: [AssignExpr] ... = ...
|
||||
# 16| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 16| getAnOperand/getLeftOperand: [LocalVariableAccess] n
|
||||
# 16| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 17| getStmt: [AssignAddExpr] ... += ...
|
||||
# 17| getDesugared: [AssignExpr] ... = ...
|
||||
# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
|
||||
@@ -633,11 +636,19 @@ control/loops.rb:
|
||||
# 18| getAnOperand/getRightOperand: [SubExpr] ... - ...
|
||||
# 18| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
|
||||
# 18| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n
|
||||
# 16| getReceiver: [RangeLiteral] _ .. _
|
||||
# 16| getBegin: [IntegerLiteral] 1
|
||||
# 16| getEnd: [IntegerLiteral] 10
|
||||
# 22| [ForExpr] for ... in ...
|
||||
# 22| getDesugared: [MethodCall] call to each
|
||||
# 22| getReceiver: [HashLiteral] {...}
|
||||
# 22| getDesugared: [MethodCall] call to []
|
||||
# 22| getReceiver: [ConstantReadAccess] Hash
|
||||
# 22| getArgument: [Pair] Pair
|
||||
# 22| getKey: [SymbolLiteral] :foo
|
||||
# 22| getComponent: [StringTextComponent] foo
|
||||
# 22| getValue: [IntegerLiteral] 0
|
||||
# 22| getArgument: [Pair] Pair
|
||||
# 22| getKey: [SymbolLiteral] :bar
|
||||
# 22| getComponent: [StringTextComponent] bar
|
||||
# 22| getValue: [IntegerLiteral] 1
|
||||
# 22| getBlock: [BraceBlock] { ... }
|
||||
# 22| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 22| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
@@ -670,19 +681,19 @@ control/loops.rb:
|
||||
# 24| getAnOperand/getRightOperand: [MulExpr] ... * ...
|
||||
# 24| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
|
||||
# 24| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
|
||||
# 22| getReceiver: [HashLiteral] {...}
|
||||
# 22| getDesugared: [MethodCall] call to []
|
||||
# 22| getReceiver: [ConstantReadAccess] Hash
|
||||
# 22| getArgument: [Pair] Pair
|
||||
# 22| getKey: [SymbolLiteral] :foo
|
||||
# 22| getComponent: [StringTextComponent] foo
|
||||
# 22| getValue: [IntegerLiteral] 0
|
||||
# 22| getArgument: [Pair] Pair
|
||||
# 22| getKey: [SymbolLiteral] :bar
|
||||
# 22| getComponent: [StringTextComponent] bar
|
||||
# 22| getValue: [IntegerLiteral] 1
|
||||
# 28| [ForExpr] for ... in ...
|
||||
# 28| getDesugared: [MethodCall] call to each
|
||||
# 28| getReceiver: [HashLiteral] {...}
|
||||
# 28| getDesugared: [MethodCall] call to []
|
||||
# 28| getReceiver: [ConstantReadAccess] Hash
|
||||
# 28| getArgument: [Pair] Pair
|
||||
# 28| getKey: [SymbolLiteral] :foo
|
||||
# 28| getComponent: [StringTextComponent] foo
|
||||
# 28| getValue: [IntegerLiteral] 0
|
||||
# 28| getArgument: [Pair] Pair
|
||||
# 28| getKey: [SymbolLiteral] :bar
|
||||
# 28| getComponent: [StringTextComponent] bar
|
||||
# 28| getValue: [IntegerLiteral] 1
|
||||
# 28| getBlock: [BraceBlock] { ... }
|
||||
# 28| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 28| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
@@ -716,17 +727,6 @@ control/loops.rb:
|
||||
# 30| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
|
||||
# 30| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
|
||||
# 31| getStmt: [BreakStmt] break
|
||||
# 28| getReceiver: [HashLiteral] {...}
|
||||
# 28| getDesugared: [MethodCall] call to []
|
||||
# 28| getReceiver: [ConstantReadAccess] Hash
|
||||
# 28| getArgument: [Pair] Pair
|
||||
# 28| getKey: [SymbolLiteral] :foo
|
||||
# 28| getComponent: [StringTextComponent] foo
|
||||
# 28| getValue: [IntegerLiteral] 0
|
||||
# 28| getArgument: [Pair] Pair
|
||||
# 28| getKey: [SymbolLiteral] :bar
|
||||
# 28| getComponent: [StringTextComponent] bar
|
||||
# 28| getValue: [IntegerLiteral] 1
|
||||
# 36| [AssignAddExpr] ... += ...
|
||||
# 36| getDesugared: [AssignExpr] ... = ...
|
||||
# 36| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
@@ -916,8 +916,8 @@ operations/operations.rb:
|
||||
# 101| [AssignLogicalOrExpr] ... ||= ...
|
||||
# 101| getDesugared: [StmtSequence] ...
|
||||
# 101| getStmt: [AssignExpr] ... = ...
|
||||
# 101| getAnOperand/getRightOperand: [ConstantReadAccess] Foo
|
||||
# 101| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 101| getAnOperand/getRightOperand: [ConstantReadAccess] Foo
|
||||
# 101| getStmt: [AssignExpr] ... = ...
|
||||
# 101| getAnOperand/getLeftOperand: [ConstantAssignment] MemberConstant
|
||||
# 101| getScopeExpr: [LocalVariableAccess] __synth__0
|
||||
@@ -928,11 +928,11 @@ operations/operations.rb:
|
||||
# 102| [AssignLogicalOrExpr] ... ||= ...
|
||||
# 102| getDesugared: [StmtSequence] ...
|
||||
# 102| getStmt: [AssignExpr] ... = ...
|
||||
# 102| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 102| getAnOperand/getRightOperand: [MethodCall] call to bar
|
||||
# 102| getReceiver: [MethodCall] call to foo
|
||||
# 102| getReceiver: [SelfVariableAccess] self
|
||||
# 102| getArgument: [IntegerLiteral] 1
|
||||
# 102| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 102| getStmt: [AssignExpr] ... = ...
|
||||
# 102| getAnOperand/getLeftOperand: [ConstantAssignment] OtherConstant
|
||||
# 102| getScopeExpr: [LocalVariableAccess] __synth__0
|
||||
@@ -949,6 +949,18 @@ operations/operations.rb:
|
||||
# 104| [AssignExpr] ... = ...
|
||||
# 104| getDesugared: [StmtSequence] ...
|
||||
# 104| getStmt: [AssignExpr] ... = ...
|
||||
# 104| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 104| getAnOperand/getRightOperand: [LocalVariableAccess] foo
|
||||
# 104| getStmt: [AssignExpr] ... = ...
|
||||
# 104| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 104| getAnOperand/getRightOperand: [SplatExpr] * ...
|
||||
# 104| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...]
|
||||
# 104| getDesugared: [MethodCall] call to []
|
||||
# 104| getReceiver: [ConstantReadAccess] Array
|
||||
# 104| getArgument: [IntegerLiteral] 1
|
||||
# 104| getArgument: [IntegerLiteral] 2
|
||||
# 104| getArgument: [IntegerLiteral] 3
|
||||
# 104| getStmt: [AssignExpr] ... = ...
|
||||
# 104| getAnOperand/getLeftOperand: [ConstantAssignment] FOO
|
||||
# 104| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 104| getReceiver: [LocalVariableAccess] __synth__3
|
||||
@@ -959,23 +971,11 @@ operations/operations.rb:
|
||||
# 104| getReceiver: [LocalVariableAccess] __synth__3
|
||||
# 104| getArgument: [IntegerLiteral] 1
|
||||
# 104| getStmt: [AssignExpr] ... = ...
|
||||
# 104| getAnOperand/getRightOperand: [LocalVariableAccess] foo
|
||||
# 104| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 104| getStmt: [AssignExpr] ... = ...
|
||||
# 104| getAnOperand/getLeftOperand: [ConstantAssignment] FOO
|
||||
# 104| getScopeExpr: [LocalVariableAccess] __synth__2
|
||||
# 104| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 104| getReceiver: [LocalVariableAccess] __synth__3
|
||||
# 104| getArgument: [IntegerLiteral] 2
|
||||
# 104| getStmt: [AssignExpr] ... = ...
|
||||
# 104| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 104| getAnOperand/getRightOperand: [SplatExpr] * ...
|
||||
# 104| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...]
|
||||
# 104| getDesugared: [MethodCall] call to []
|
||||
# 104| getReceiver: [ConstantReadAccess] Array
|
||||
# 104| getArgument: [IntegerLiteral] 1
|
||||
# 104| getArgument: [IntegerLiteral] 2
|
||||
# 104| getArgument: [IntegerLiteral] 3
|
||||
params/params.rb:
|
||||
# 8| [HashLiteral] {...}
|
||||
# 8| getDesugared: [MethodCall] call to []
|
||||
@@ -986,19 +986,6 @@ params/params.rb:
|
||||
erb/template.html.erb:
|
||||
# 27| [ForExpr] for ... in ...
|
||||
# 27| getDesugared: [MethodCall] call to each
|
||||
# 27| getBlock: [BraceBlock] { ... }
|
||||
# 27| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 27| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
# 27| getStmt: [AssignExpr] ... = ...
|
||||
# 27| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 27| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 28| getStmt: [AssignAddExpr] ... += ...
|
||||
# 28| getDesugared: [AssignExpr] ... = ...
|
||||
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] xs
|
||||
# 28| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 28| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] xs
|
||||
# 28| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] x
|
||||
# 29| getStmt: [LocalVariableAccess] xs
|
||||
# 27| getReceiver: [ArrayLiteral] [...]
|
||||
# 27| getDesugared: [MethodCall] call to []
|
||||
# 27| getReceiver: [ConstantReadAccess] Array
|
||||
@@ -1008,82 +995,95 @@ erb/template.html.erb:
|
||||
# 27| getComponent: [StringTextComponent] bar
|
||||
# 27| getArgument: [StringLiteral] "baz"
|
||||
# 27| getComponent: [StringTextComponent] baz
|
||||
# 27| getBlock: [BraceBlock] { ... }
|
||||
# 27| getParameter: [SimpleParameter] __synth__0__1
|
||||
# 27| getDefiningAccess: [LocalVariableAccess] __synth__0__1
|
||||
# 27| getStmt: [AssignExpr] ... = ...
|
||||
# 27| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 27| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 28| getStmt: [AssignAddExpr] ... += ...
|
||||
# 28| getDesugared: [AssignExpr] ... = ...
|
||||
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] xs
|
||||
# 28| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 28| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] xs
|
||||
# 28| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] x
|
||||
# 29| getStmt: [LocalVariableAccess] xs
|
||||
gems/test.gemspec:
|
||||
# 2| [AssignExpr] ... = ...
|
||||
# 2| getDesugared: [StmtSequence] ...
|
||||
# 2| getStmt: [SetterMethodCall] call to name=
|
||||
# 2| getReceiver: [LocalVariableAccess] s
|
||||
# 2| getArgument: [AssignExpr] ... = ...
|
||||
# 2| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 2| getAnOperand/getRightOperand: [StringLiteral] "test"
|
||||
# 2| getComponent: [StringTextComponent] test
|
||||
# 2| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 2| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 3| [AssignExpr] ... = ...
|
||||
# 3| getDesugared: [StmtSequence] ...
|
||||
# 3| getStmt: [SetterMethodCall] call to version=
|
||||
# 3| getReceiver: [LocalVariableAccess] s
|
||||
# 3| getArgument: [AssignExpr] ... = ...
|
||||
# 3| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 3| getAnOperand/getRightOperand: [StringLiteral] "0.0.0"
|
||||
# 3| getComponent: [StringTextComponent] 0.0.0
|
||||
# 3| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 3| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 4| [AssignExpr] ... = ...
|
||||
# 4| getDesugared: [StmtSequence] ...
|
||||
# 4| getStmt: [SetterMethodCall] call to summary=
|
||||
# 4| getReceiver: [LocalVariableAccess] s
|
||||
# 4| getArgument: [AssignExpr] ... = ...
|
||||
# 4| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 4| getAnOperand/getRightOperand: [StringLiteral] "foo!"
|
||||
# 4| getComponent: [StringTextComponent] foo!
|
||||
# 4| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 4| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 5| [AssignExpr] ... = ...
|
||||
# 5| getDesugared: [StmtSequence] ...
|
||||
# 5| getStmt: [SetterMethodCall] call to description=
|
||||
# 5| getReceiver: [LocalVariableAccess] s
|
||||
# 5| getArgument: [AssignExpr] ... = ...
|
||||
# 5| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 5| getAnOperand/getRightOperand: [StringLiteral] "A test"
|
||||
# 5| getComponent: [StringTextComponent] A test
|
||||
# 5| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 5| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 6| [AssignExpr] ... = ...
|
||||
# 6| getDesugared: [StmtSequence] ...
|
||||
# 6| getStmt: [SetterMethodCall] call to authors=
|
||||
# 6| getReceiver: [LocalVariableAccess] s
|
||||
# 6| getArgument: [AssignExpr] ... = ...
|
||||
# 6| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 6| getAnOperand/getRightOperand: [ArrayLiteral] [...]
|
||||
# 6| getDesugared: [MethodCall] call to []
|
||||
# 6| getReceiver: [ConstantReadAccess] Array
|
||||
# 6| getArgument: [StringLiteral] "Mona Lisa"
|
||||
# 6| getComponent: [StringTextComponent] Mona Lisa
|
||||
# 6| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 6| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 7| [AssignExpr] ... = ...
|
||||
# 7| getDesugared: [StmtSequence] ...
|
||||
# 7| getStmt: [SetterMethodCall] call to email=
|
||||
# 7| getReceiver: [LocalVariableAccess] s
|
||||
# 7| getArgument: [AssignExpr] ... = ...
|
||||
# 7| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 7| getAnOperand/getRightOperand: [StringLiteral] "mona@example.com"
|
||||
# 7| getComponent: [StringTextComponent] mona@example.com
|
||||
# 7| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 7| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 8| [AssignExpr] ... = ...
|
||||
# 8| getDesugared: [StmtSequence] ...
|
||||
# 8| getStmt: [SetterMethodCall] call to files=
|
||||
# 8| getReceiver: [LocalVariableAccess] s
|
||||
# 8| getArgument: [AssignExpr] ... = ...
|
||||
# 8| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 8| getAnOperand/getRightOperand: [ArrayLiteral] [...]
|
||||
# 8| getDesugared: [MethodCall] call to []
|
||||
# 8| getReceiver: [ConstantReadAccess] Array
|
||||
# 8| getArgument: [StringLiteral] "lib/test.rb"
|
||||
# 8| getComponent: [StringTextComponent] lib/test.rb
|
||||
# 8| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 8| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 9| [AssignExpr] ... = ...
|
||||
# 9| getDesugared: [StmtSequence] ...
|
||||
# 9| getStmt: [SetterMethodCall] call to homepage=
|
||||
# 9| getReceiver: [LocalVariableAccess] s
|
||||
# 9| getArgument: [AssignExpr] ... = ...
|
||||
# 9| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 9| getAnOperand/getRightOperand: [StringLiteral] "https://github.com/github/cod..."
|
||||
# 9| getComponent: [StringTextComponent] https://github.com/github/codeql-ruby
|
||||
# 9| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 9| getStmt: [LocalVariableAccess] __synth__0
|
||||
|
||||
@@ -77,12 +77,12 @@ callsWithArguments
|
||||
| calls.rb:319:14:319:22 | call to [] | [] | 0 | calls.rb:319:15:319:15 | 1 |
|
||||
| calls.rb:319:14:319:22 | call to [] | [] | 1 | calls.rb:319:18:319:18 | 2 |
|
||||
| calls.rb:319:14:319:22 | call to [] | [] | 2 | calls.rb:319:21:319:21 | 3 |
|
||||
| calls.rb:320:1:320:10 | call to count= | count= | 1 | calls.rb:320:12:320:13 | __synth__1 |
|
||||
| calls.rb:320:1:320:10 | call to count= | count= | 0 | calls.rb:320:1:320:10 | __synth__1 |
|
||||
| calls.rb:320:12:320:13 | ... + ... | + | 0 | calls.rb:320:15:320:15 | 1 |
|
||||
| calls.rb:321:1:321:6 | ...[...] | [] | 0 | calls.rb:321:5:321:5 | 0 |
|
||||
| calls.rb:321:1:321:6 | call to [] | [] | 0 | calls.rb:321:5:321:5 | __synth__1 |
|
||||
| calls.rb:321:1:321:6 | call to []= | []= | 0 | calls.rb:321:5:321:5 | __synth__1 |
|
||||
| calls.rb:321:1:321:6 | call to []= | []= | 2 | calls.rb:321:8:321:9 | __synth__2 |
|
||||
| calls.rb:321:1:321:6 | call to []= | []= | 1 | calls.rb:321:1:321:6 | __synth__2 |
|
||||
| calls.rb:321:8:321:9 | ... + ... | + | 0 | calls.rb:321:11:321:11 | 1 |
|
||||
| calls.rb:322:1:322:32 | ...[...] | [] | 0 | calls.rb:322:9:322:9 | 0 |
|
||||
| calls.rb:322:1:322:32 | ...[...] | [] | 1 | calls.rb:322:12:322:18 | call to baz |
|
||||
@@ -93,7 +93,7 @@ callsWithArguments
|
||||
| calls.rb:322:1:322:32 | call to []= | []= | 0 | calls.rb:322:9:322:9 | __synth__1 |
|
||||
| calls.rb:322:1:322:32 | call to []= | []= | 1 | calls.rb:322:12:322:18 | __synth__2 |
|
||||
| calls.rb:322:1:322:32 | call to []= | []= | 2 | calls.rb:322:21:322:31 | __synth__3 |
|
||||
| calls.rb:322:1:322:32 | call to []= | []= | 4 | calls.rb:322:34:322:35 | __synth__4 |
|
||||
| calls.rb:322:1:322:32 | call to []= | []= | 3 | calls.rb:322:1:322:32 | __synth__4 |
|
||||
| calls.rb:322:21:322:31 | ... + ... | + | 0 | calls.rb:322:31:322:31 | 1 |
|
||||
| calls.rb:322:34:322:35 | ... * ... | * | 0 | calls.rb:322:37:322:37 | 2 |
|
||||
| calls.rb:330:25:330:37 | call to print | print | 0 | calls.rb:330:31:330:37 | "error" |
|
||||
|
||||
@@ -4004,6 +4004,9 @@ desugar.rb:
|
||||
# 14| call to foo
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 14| __synth__1
|
||||
#-----| -> call to count=
|
||||
|
||||
# 14| call to count
|
||||
#-----| -> 1
|
||||
|
||||
@@ -4025,9 +4028,6 @@ desugar.rb:
|
||||
# 14| __synth__1
|
||||
#-----| -> __synth__0
|
||||
|
||||
# 14| __synth__1
|
||||
#-----| -> call to count=
|
||||
|
||||
# 14| 1
|
||||
#-----| -> ... + ...
|
||||
|
||||
@@ -4066,6 +4066,9 @@ desugar.rb:
|
||||
# 18| call to foo
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 18| __synth__4
|
||||
#-----| -> call to []=
|
||||
|
||||
# 18| call to []
|
||||
#-----| -> 1
|
||||
|
||||
@@ -4144,9 +4147,6 @@ desugar.rb:
|
||||
# 18| __synth__4
|
||||
#-----| -> __synth__0
|
||||
|
||||
# 18| __synth__4
|
||||
#-----| -> call to []=
|
||||
|
||||
# 18| 1
|
||||
#-----| -> ... + ...
|
||||
|
||||
|
||||
@@ -219,15 +219,15 @@ positionalArguments
|
||||
| desugar.rb:6:3:6:13 | call to count= | desugar.rb:6:17:6:17 | ... = ... |
|
||||
| desugar.rb:10:3:10:10 | call to []= | desugar.rb:10:9:10:9 | 0 |
|
||||
| desugar.rb:10:3:10:10 | call to []= | desugar.rb:10:14:10:14 | ... = ... |
|
||||
| desugar.rb:14:3:14:13 | call to count= | desugar.rb:14:15:14:16 | __synth__1 |
|
||||
| desugar.rb:14:3:14:13 | call to count= | desugar.rb:14:3:14:13 | __synth__1 |
|
||||
| desugar.rb:14:15:14:16 | ... + ... | desugar.rb:14:18:14:18 | 1 |
|
||||
| desugar.rb:18:3:18:28 | call to [] | desugar.rb:18:9:18:9 | __synth__1 |
|
||||
| desugar.rb:18:3:18:28 | call to [] | desugar.rb:18:12:18:16 | __synth__2 |
|
||||
| desugar.rb:18:3:18:28 | call to [] | desugar.rb:18:19:18:27 | __synth__3 |
|
||||
| desugar.rb:18:3:18:28 | call to []= | desugar.rb:18:3:18:28 | __synth__4 |
|
||||
| desugar.rb:18:3:18:28 | call to []= | desugar.rb:18:9:18:9 | __synth__1 |
|
||||
| desugar.rb:18:3:18:28 | call to []= | desugar.rb:18:12:18:16 | __synth__2 |
|
||||
| desugar.rb:18:3:18:28 | call to []= | desugar.rb:18:19:18:27 | __synth__3 |
|
||||
| desugar.rb:18:3:18:28 | call to []= | desugar.rb:18:30:18:31 | __synth__4 |
|
||||
| desugar.rb:18:19:18:27 | ... + ... | desugar.rb:18:27:18:27 | 3 |
|
||||
| desugar.rb:18:30:18:31 | ... + ... | desugar.rb:18:33:18:33 | 1 |
|
||||
| desugar.rb:22:3:22:3 | call to [] | desugar.rb:22:3:22:3 | 0 |
|
||||
|
||||
@@ -36,6 +36,12 @@
|
||||
#-----| TrueClass
|
||||
#-----| super -> Object
|
||||
|
||||
#-----| UnresolvedNamespace::X1
|
||||
|
||||
#-----| UnresolvedNamespace::X1::X2
|
||||
|
||||
#-----| UnresolvedNamespace::X1::X2::X3
|
||||
|
||||
calls.rb:
|
||||
# 21| M
|
||||
|
||||
@@ -272,3 +278,12 @@ unresolved_subclass.rb:
|
||||
|
||||
# 11| UnresolvedNamespace::A
|
||||
#-----| super -> Object
|
||||
|
||||
# 14| UnresolvedNamespace::X1::X2::X3::Subclass1
|
||||
#-----| super -> ResolvableBaseClass
|
||||
|
||||
# 17| UnresolvedNamespace::X1::X2::X3::Subclass2
|
||||
#-----| super -> UnresolvedNamespace::X1::X2::X3::Subclass1
|
||||
|
||||
# 21| UnresolvedNamespace::X1::X2::X3::A
|
||||
#-----| super -> Object
|
||||
|
||||
@@ -660,6 +660,15 @@ lookupMethod
|
||||
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | new | calls.rb:117:5:117:16 | new |
|
||||
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | puts | calls.rb:102:5:102:30 | puts |
|
||||
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| unresolved_subclass.rb:14:1:15:3 | UnresolvedNamespace::X1::X2::X3::Subclass1 | new | calls.rb:117:5:117:16 | new |
|
||||
| unresolved_subclass.rb:14:1:15:3 | UnresolvedNamespace::X1::X2::X3::Subclass1 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| unresolved_subclass.rb:14:1:15:3 | UnresolvedNamespace::X1::X2::X3::Subclass1 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| unresolved_subclass.rb:17:1:18:3 | UnresolvedNamespace::X1::X2::X3::Subclass2 | new | calls.rb:117:5:117:16 | new |
|
||||
| unresolved_subclass.rb:17:1:18:3 | UnresolvedNamespace::X1::X2::X3::Subclass2 | puts | calls.rb:102:5:102:30 | puts |
|
||||
| unresolved_subclass.rb:17:1:18:3 | UnresolvedNamespace::X1::X2::X3::Subclass2 | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
| unresolved_subclass.rb:21:1:22:3 | UnresolvedNamespace::X1::X2::X3::A | new | calls.rb:117:5:117:16 | new |
|
||||
| unresolved_subclass.rb:21:1:22:3 | UnresolvedNamespace::X1::X2::X3::A | puts | calls.rb:102:5:102:30 | puts |
|
||||
| unresolved_subclass.rb:21:1:22:3 | UnresolvedNamespace::X1::X2::X3::A | to_s | calls.rb:172:5:173:7 | to_s |
|
||||
enclosingMethod
|
||||
| calls.rb:2:5:2:14 | call to puts | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:2:5:2:14 | self | calls.rb:1:1:3:3 | foo |
|
||||
|
||||
@@ -51,6 +51,9 @@ getModule
|
||||
| file://:0:0:0:0 | Symbol |
|
||||
| file://:0:0:0:0 | TrueClass |
|
||||
| file://:0:0:0:0 | UnresolvedNamespace |
|
||||
| file://:0:0:0:0 | UnresolvedNamespace::X1 |
|
||||
| file://:0:0:0:0 | UnresolvedNamespace::X1::X2 |
|
||||
| file://:0:0:0:0 | UnresolvedNamespace::X1::X2::X3 |
|
||||
| hello.rb:1:1:8:3 | EnglishWords |
|
||||
| hello.rb:11:1:16:3 | Greeting |
|
||||
| hello.rb:18:1:22:3 | HelloWorld |
|
||||
@@ -97,6 +100,9 @@ getModule
|
||||
| unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 |
|
||||
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 |
|
||||
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A |
|
||||
| unresolved_subclass.rb:14:1:15:3 | UnresolvedNamespace::X1::X2::X3::Subclass1 |
|
||||
| unresolved_subclass.rb:17:1:18:3 | UnresolvedNamespace::X1::X2::X3::Subclass2 |
|
||||
| unresolved_subclass.rb:21:1:22:3 | UnresolvedNamespace::X1::X2::X3::A |
|
||||
getADeclaration
|
||||
| calls.rb:21:1:34:3 | M | calls.rb:21:1:34:3 | M |
|
||||
| calls.rb:43:1:58:3 | C | calls.rb:43:1:58:3 | C |
|
||||
@@ -113,7 +119,7 @@ getADeclaration
|
||||
| calls.rb:115:1:118:3 | Object | modules_rec.rb:1:1:11:26 | modules_rec.rb |
|
||||
| calls.rb:115:1:118:3 | Object | private.rb:1:1:105:40 | private.rb |
|
||||
| calls.rb:115:1:118:3 | Object | toplevel_self_singleton.rb:1:1:34:4 | toplevel_self_singleton.rb |
|
||||
| calls.rb:115:1:118:3 | Object | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| calls.rb:115:1:118:3 | Object | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| calls.rb:120:1:123:3 | Hash | calls.rb:120:1:123:3 | Hash |
|
||||
| calls.rb:125:1:138:3 | Array | calls.rb:125:1:138:3 | Array |
|
||||
| calls.rb:165:1:169:3 | S | calls.rb:165:1:169:3 | S |
|
||||
@@ -197,6 +203,9 @@ getADeclaration
|
||||
| unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 | unresolved_subclass.rb:4:1:5:3 | Subclass1 |
|
||||
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 | unresolved_subclass.rb:7:1:8:3 | Subclass2 |
|
||||
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | unresolved_subclass.rb:11:1:12:3 | A |
|
||||
| unresolved_subclass.rb:14:1:15:3 | UnresolvedNamespace::X1::X2::X3::Subclass1 | unresolved_subclass.rb:14:1:15:3 | Subclass1 |
|
||||
| unresolved_subclass.rb:17:1:18:3 | UnresolvedNamespace::X1::X2::X3::Subclass2 | unresolved_subclass.rb:17:1:18:3 | Subclass2 |
|
||||
| unresolved_subclass.rb:21:1:22:3 | UnresolvedNamespace::X1::X2::X3::A | unresolved_subclass.rb:21:1:22:3 | A |
|
||||
getSuperClass
|
||||
| calls.rb:43:1:58:3 | C | calls.rb:115:1:118:3 | Object |
|
||||
| calls.rb:65:1:69:3 | D | calls.rb:43:1:58:3 | C |
|
||||
@@ -259,6 +268,9 @@ getSuperClass
|
||||
| unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 | unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass |
|
||||
| unresolved_subclass.rb:7:1:8:3 | UnresolvedNamespace::Subclass2 | unresolved_subclass.rb:4:1:5:3 | UnresolvedNamespace::Subclass1 |
|
||||
| unresolved_subclass.rb:11:1:12:3 | UnresolvedNamespace::A | calls.rb:115:1:118:3 | Object |
|
||||
| unresolved_subclass.rb:14:1:15:3 | UnresolvedNamespace::X1::X2::X3::Subclass1 | unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass |
|
||||
| unresolved_subclass.rb:17:1:18:3 | UnresolvedNamespace::X1::X2::X3::Subclass2 | unresolved_subclass.rb:14:1:15:3 | UnresolvedNamespace::X1::X2::X3::Subclass1 |
|
||||
| unresolved_subclass.rb:21:1:22:3 | UnresolvedNamespace::X1::X2::X3::A | calls.rb:115:1:118:3 | Object |
|
||||
getAPrependedModule
|
||||
| calls.rb:115:1:118:3 | Object | calls.rb:171:1:174:3 | A |
|
||||
| calls.rb:171:1:174:3 | A | toplevel_self_singleton.rb:2:5:5:7 | A::B |
|
||||
@@ -419,6 +431,28 @@ resolveConstantReadAccess
|
||||
| unresolved_subclass.rb:7:40:7:69 | Subclass1 | UnresolvedNamespace::Subclass1 |
|
||||
| unresolved_subclass.rb:11:7:11:25 | UnresolvedNamespace | UnresolvedNamespace |
|
||||
| unresolved_subclass.rb:11:32:11:50 | UnresolvedNamespace | UnresolvedNamespace |
|
||||
| unresolved_subclass.rb:14:7:14:25 | UnresolvedNamespace | UnresolvedNamespace |
|
||||
| unresolved_subclass.rb:14:7:14:29 | X1 | UnresolvedNamespace::X1 |
|
||||
| unresolved_subclass.rb:14:7:14:33 | X2 | UnresolvedNamespace::X1::X2 |
|
||||
| unresolved_subclass.rb:14:7:14:37 | X3 | UnresolvedNamespace::X1::X2::X3 |
|
||||
| unresolved_subclass.rb:14:52:14:70 | ResolvableBaseClass | ResolvableBaseClass |
|
||||
| unresolved_subclass.rb:17:7:17:25 | UnresolvedNamespace | UnresolvedNamespace |
|
||||
| unresolved_subclass.rb:17:7:17:29 | X1 | UnresolvedNamespace::X1 |
|
||||
| unresolved_subclass.rb:17:7:17:33 | X2 | UnresolvedNamespace::X1::X2 |
|
||||
| unresolved_subclass.rb:17:7:17:37 | X3 | UnresolvedNamespace::X1::X2::X3 |
|
||||
| unresolved_subclass.rb:17:52:17:70 | UnresolvedNamespace | UnresolvedNamespace |
|
||||
| unresolved_subclass.rb:17:52:17:74 | X1 | UnresolvedNamespace::X1 |
|
||||
| unresolved_subclass.rb:17:52:17:78 | X2 | UnresolvedNamespace::X1::X2 |
|
||||
| unresolved_subclass.rb:17:52:17:82 | X3 | UnresolvedNamespace::X1::X2::X3 |
|
||||
| unresolved_subclass.rb:17:52:17:93 | Subclass1 | UnresolvedNamespace::X1::X2::X3::Subclass1 |
|
||||
| unresolved_subclass.rb:21:7:21:25 | UnresolvedNamespace | UnresolvedNamespace |
|
||||
| unresolved_subclass.rb:21:7:21:29 | X1 | UnresolvedNamespace::X1 |
|
||||
| unresolved_subclass.rb:21:7:21:33 | X2 | UnresolvedNamespace::X1::X2 |
|
||||
| unresolved_subclass.rb:21:7:21:37 | X3 | UnresolvedNamespace::X1::X2::X3 |
|
||||
| unresolved_subclass.rb:21:44:21:62 | UnresolvedNamespace | UnresolvedNamespace |
|
||||
| unresolved_subclass.rb:21:44:21:66 | X1 | UnresolvedNamespace::X1 |
|
||||
| unresolved_subclass.rb:21:44:21:70 | X2 | UnresolvedNamespace::X1::X2 |
|
||||
| unresolved_subclass.rb:21:44:21:74 | X3 | UnresolvedNamespace::X1::X2::X3 |
|
||||
resolveConstantWriteAccess
|
||||
| calls.rb:21:1:34:3 | M | M |
|
||||
| calls.rb:43:1:58:3 | C | C |
|
||||
@@ -523,6 +557,9 @@ resolveConstantWriteAccess
|
||||
| unresolved_subclass.rb:4:1:5:3 | Subclass1 | UnresolvedNamespace::Subclass1 |
|
||||
| unresolved_subclass.rb:7:1:8:3 | Subclass2 | UnresolvedNamespace::Subclass2 |
|
||||
| unresolved_subclass.rb:11:1:12:3 | A | UnresolvedNamespace::A |
|
||||
| unresolved_subclass.rb:14:1:15:3 | Subclass1 | UnresolvedNamespace::X1::X2::X3::Subclass1 |
|
||||
| unresolved_subclass.rb:17:1:18:3 | Subclass2 | UnresolvedNamespace::X1::X2::X3::Subclass2 |
|
||||
| unresolved_subclass.rb:21:1:22:3 | A | UnresolvedNamespace::X1::X2::X3::A |
|
||||
enclosingModule
|
||||
| calls.rb:1:1:3:3 | foo | calls.rb:1:1:651:24 | calls.rb |
|
||||
| calls.rb:2:5:2:14 | call to puts | calls.rb:1:1:651:24 | calls.rb |
|
||||
@@ -1878,15 +1915,41 @@ enclosingModule
|
||||
| toplevel_self_singleton.rb:30:13:30:19 | self | toplevel_self_singleton.rb:25:5:33:7 | class << ... |
|
||||
| toplevel_self_singleton.rb:31:13:31:20 | call to call_you | toplevel_self_singleton.rb:25:5:33:7 | class << ... |
|
||||
| toplevel_self_singleton.rb:31:13:31:20 | self | toplevel_self_singleton.rb:25:5:33:7 | class << ... |
|
||||
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:4:1:5:3 | Subclass1 | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:4:7:4:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:4:40:4:58 | ResolvableBaseClass | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:1:8:3 | Subclass2 | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:7:7:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:40:7:58 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:40:7:69 | Subclass1 | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:1:12:3 | A | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:7:11:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:32:11:50 | UnresolvedNamespace | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:32:11:53 | B | unresolved_subclass.rb:1:1:12:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:1:1:2:3 | ResolvableBaseClass | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:4:1:5:3 | Subclass1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:4:7:4:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:4:40:4:58 | ResolvableBaseClass | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:1:8:3 | Subclass2 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:7:7:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:40:7:58 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:7:40:7:69 | Subclass1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:1:12:3 | A | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:7:11:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:32:11:50 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:11:32:11:53 | B | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:14:1:15:3 | Subclass1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:14:7:14:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:14:7:14:29 | X1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:14:7:14:33 | X2 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:14:7:14:37 | X3 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:14:52:14:70 | ResolvableBaseClass | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:1:18:3 | Subclass2 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:7:17:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:7:17:29 | X1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:7:17:33 | X2 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:7:17:37 | X3 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:52:17:70 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:52:17:74 | X1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:52:17:78 | X2 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:52:17:82 | X3 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:17:52:17:93 | Subclass1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:1:22:3 | A | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:7:21:25 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:7:21:29 | X1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:7:21:33 | X2 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:7:21:37 | X3 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:44:21:62 | UnresolvedNamespace | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:44:21:66 | X1 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:44:21:70 | X2 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:44:21:74 | X3 | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
| unresolved_subclass.rb:21:44:21:77 | B | unresolved_subclass.rb:1:1:22:4 | unresolved_subclass.rb |
|
||||
|
||||
@@ -36,6 +36,12 @@
|
||||
#-----| TrueClass
|
||||
#-----| -> Object
|
||||
|
||||
#-----| UnresolvedNamespace::X1
|
||||
|
||||
#-----| UnresolvedNamespace::X1::X2
|
||||
|
||||
#-----| UnresolvedNamespace::X1::X2::X3
|
||||
|
||||
calls.rb:
|
||||
# 21| M
|
||||
|
||||
@@ -262,3 +268,12 @@ unresolved_subclass.rb:
|
||||
|
||||
# 11| UnresolvedNamespace::A
|
||||
#-----| -> Object
|
||||
|
||||
# 14| UnresolvedNamespace::X1::X2::X3::Subclass1
|
||||
#-----| -> ResolvableBaseClass
|
||||
|
||||
# 17| UnresolvedNamespace::X1::X2::X3::Subclass2
|
||||
#-----| -> UnresolvedNamespace::X1::X2::X3::Subclass1
|
||||
|
||||
# 21| UnresolvedNamespace::X1::X2::X3::A
|
||||
#-----| -> Object
|
||||
|
||||
@@ -10,3 +10,13 @@ end
|
||||
# Ensure Object is a transitive superclass of this
|
||||
class UnresolvedNamespace::A < UnresolvedNamespace::B
|
||||
end
|
||||
|
||||
class UnresolvedNamespace::X1::X2::X3::Subclass1 < ResolvableBaseClass
|
||||
end
|
||||
|
||||
class UnresolvedNamespace::X1::X2::X3::Subclass2 < UnresolvedNamespace::X1::X2::X3::Subclass1
|
||||
end
|
||||
|
||||
# Ensure Object is a transitive superclass of this
|
||||
class UnresolvedNamespace::X1::X2::X3::A < UnresolvedNamespace::X1::X2::X3::B
|
||||
end
|
||||
|
||||
@@ -1,26 +1,3 @@
|
||||
edges
|
||||
| app/controllers/users_controller.rb:4:11:4:16 | call to params : | app/controllers/users_controller.rb:4:11:4:27 | ...[...] |
|
||||
| app/controllers/users_controller.rb:9:5:9:12 | password : | app/controllers/users_controller.rb:10:42:10:49 | password |
|
||||
| app/controllers/users_controller.rb:9:16:9:21 | call to params : | app/controllers/users_controller.rb:9:16:9:27 | ...[...] : |
|
||||
| app/controllers/users_controller.rb:9:16:9:27 | ...[...] : | app/controllers/users_controller.rb:9:5:9:12 | password : |
|
||||
| app/controllers/users_controller.rb:14:5:14:13 | [post] self [@password] : | app/controllers/users_controller.rb:15:42:15:50 | self [@password] : |
|
||||
| app/controllers/users_controller.rb:14:17:14:22 | call to params : | app/controllers/users_controller.rb:14:17:14:28 | ...[...] : |
|
||||
| app/controllers/users_controller.rb:14:17:14:28 | ...[...] : | app/controllers/users_controller.rb:14:5:14:13 | [post] self [@password] : |
|
||||
| app/controllers/users_controller.rb:15:42:15:50 | self [@password] : | app/controllers/users_controller.rb:15:42:15:50 | @password |
|
||||
nodes
|
||||
| app/controllers/users_controller.rb:4:11:4:16 | call to params : | semmle.label | call to params : |
|
||||
| app/controllers/users_controller.rb:4:11:4:27 | ...[...] | semmle.label | ...[...] |
|
||||
| app/controllers/users_controller.rb:9:5:9:12 | password : | semmle.label | password : |
|
||||
| app/controllers/users_controller.rb:9:16:9:21 | call to params : | semmle.label | call to params : |
|
||||
| app/controllers/users_controller.rb:9:16:9:27 | ...[...] : | semmle.label | ...[...] : |
|
||||
| app/controllers/users_controller.rb:10:42:10:49 | password | semmle.label | password |
|
||||
| app/controllers/users_controller.rb:14:5:14:13 | [post] self [@password] : | semmle.label | [post] self [@password] : |
|
||||
| app/controllers/users_controller.rb:14:17:14:22 | call to params : | semmle.label | call to params : |
|
||||
| app/controllers/users_controller.rb:14:17:14:28 | ...[...] : | semmle.label | ...[...] : |
|
||||
| app/controllers/users_controller.rb:15:42:15:50 | @password | semmle.label | @password |
|
||||
| app/controllers/users_controller.rb:15:42:15:50 | self [@password] : | semmle.label | self [@password] : |
|
||||
subpaths
|
||||
#select
|
||||
| app/controllers/users_controller.rb:4:11:4:16 | call to params | app/controllers/users_controller.rb:4:11:4:16 | call to params : | app/controllers/users_controller.rb:4:11:4:27 | ...[...] | $@ for GET requests uses query parameter as sensitive data. | app/controllers/users_controller.rb:3:3:6:5 | login_get_1 | Route handler |
|
||||
| app/controllers/users_controller.rb:9:16:9:21 | call to params | app/controllers/users_controller.rb:9:16:9:21 | call to params : | app/controllers/users_controller.rb:10:42:10:49 | password | $@ for GET requests uses query parameter as sensitive data. | app/controllers/users_controller.rb:8:3:11:5 | login_get_2 | Route handler |
|
||||
| app/controllers/users_controller.rb:14:17:14:22 | call to params | app/controllers/users_controller.rb:14:17:14:22 | call to params : | app/controllers/users_controller.rb:15:42:15:50 | @password | $@ for GET requests uses query parameter as sensitive data. | app/controllers/users_controller.rb:13:3:16:5 | login_get_3 | Route handler |
|
||||
| app/controllers/users_controller.rb:4:11:4:16 | call to params | $@ for GET requests uses query parameter as sensitive data. | app/controllers/users_controller.rb:3:3:6:5 | login_get_1 | Route handler |
|
||||
| app/controllers/users_controller.rb:9:16:9:21 | call to params | $@ for GET requests uses query parameter as sensitive data. | app/controllers/users_controller.rb:8:3:11:5 | login_get_2 | Route handler |
|
||||
| app/controllers/users_controller.rb:14:17:14:22 | call to params | $@ for GET requests uses query parameter as sensitive data. | app/controllers/users_controller.rb:13:3:16:5 | login_get_3 | Route handler |
|
||||
|
||||
@@ -328,7 +328,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +378,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +389,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
flowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
Reference in New Issue
Block a user