Merge branch 'main' of github.com:github/codeql into python-port-insecure-protocol

This commit is contained in:
Rasmus Lerchedahl Petersen
2021-03-15 17:37:28 +01:00
1301 changed files with 31762 additions and 8801 deletions

View File

@@ -2,7 +2,7 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="CommentedOutCodeQuery.qhelp" />
<include src="CommentedOutCodeExample.qhelp" />
<include src="CommentedOutCodeReferences.qhelp" />
<include src="CommentedOutCodeQuery.inc.qhelp" />
<include src="CommentedOutCodeExample.inc.qhelp" />
<include src="CommentedOutCodeReferences.inc.qhelp" />
</qhelp>

View File

@@ -2,7 +2,7 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="CommentedOutCodeMetricOverview.qhelp" />
<include src="CommentedOutCodeExample.qhelp" />
<include src="CommentedOutCodeReferences.qhelp" />
<include src="CommentedOutCodeMetricOverview.inc.qhelp" />
<include src="CommentedOutCodeExample.inc.qhelp" />
<include src="CommentedOutCodeReferences.inc.qhelp" />
</qhelp>

View File

@@ -2,5 +2,5 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="FLinesOfDuplicatedCodeCommon.qhelp" />
<include src="FLinesOfDuplicatedCodeCommon.inc.qhelp" />
</qhelp>

View File

@@ -14,7 +14,7 @@ for a number of reasons.
</p>
</overview>
<include src="DuplicationProblems.qhelp" />
<include src="DuplicationProblems.inc.qhelp" />
<recommendation>

View File

@@ -10,7 +10,7 @@ duplicated code.
</p>
</overview>
<include src="DuplicationProblems.qhelp" />
<include src="DuplicationProblems.inc.qhelp" />
<recommendation>

View File

@@ -11,28 +11,86 @@
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.ApiGraphs
Value aSocket() { result.getClass() = Value::named("socket.socket") }
CallNode socketBindCall() {
result = aSocket().attr("bind").(CallableValue).getACall() and major_version() = 3
or
result.getFunction().(AttrNode).getObject("bind").pointsTo(aSocket()) and
major_version() = 2
/** Gets a hostname that can be used to bind to all interfaces. */
private string vulnerableHostname() {
result in [
// IPv4
"0.0.0.0", "",
// IPv6
"::", "::0"
]
}
string allInterfaces() { result = "0.0.0.0" or result = "" }
Value getTextValue(string address) {
result = Value::forUnicode(address) and major_version() = 3
/** Gets a reference to a hostname that can be used to bind to all interfaces. */
private DataFlow::LocalSourceNode vulnerableHostnameRef(DataFlow::TypeTracker t, string hostname) {
t.start() and
exists(StrConst allInterfacesStrConst | hostname = vulnerableHostname() |
allInterfacesStrConst.getText() = hostname and
result.asExpr() = allInterfacesStrConst
)
or
result = Value::forString(address) and major_version() = 2
// Due to bad performance when using normal setup with `vulnerableHostnameRef(t2, hostname).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
vulnerableHostnameRef_first_join(t2, hostname, result, summary) and
t = t2.append(summary)
)
)
}
from CallNode call, TupleValue args, string address
pragma[nomagic]
private predicate vulnerableHostnameRef_first_join(
DataFlow::TypeTracker t2, string hostname, DataFlow::Node res, DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(vulnerableHostnameRef(t2, hostname), res, summary)
}
/** Gets a reference to a hostname that can be used to bind to all interfaces. */
DataFlow::Node vulnerableHostnameRef(string hostname) {
vulnerableHostnameRef(DataFlow::TypeTracker::end(), hostname).flowsTo(result)
}
/** Gets a reference to a tuple for which the first element is a hostname that can be used to bind to all interfaces. */
private DataFlow::LocalSourceNode vulnerableAddressTuple(DataFlow::TypeTracker t, string hostname) {
t.start() and
result.asExpr() = any(Tuple tup | tup.getElt(0) = vulnerableHostnameRef(hostname).asExpr())
or
// Due to bad performance when using normal setup with `vulnerableAddressTuple(t2, hostname).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
vulnerableAddressTuple_first_join(t2, hostname, result, summary) and
t = t2.append(summary)
)
)
}
pragma[nomagic]
private predicate vulnerableAddressTuple_first_join(
DataFlow::TypeTracker t2, string hostname, DataFlow::Node res, DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(vulnerableAddressTuple(t2, hostname), res, summary)
}
/** Gets a reference to a tuple for which the first element is a hostname that can be used to bind to all interfaces. */
DataFlow::Node vulnerableAddressTuple(string hostname) {
vulnerableAddressTuple(DataFlow::TypeTracker::end(), hostname).flowsTo(result)
}
/**
* Gets an instance of `socket.socket` using _some_ address family.
*
* See https://docs.python.org/3/library/socket.html
*/
API::Node socketInstance() { result = API::moduleImport("socket").getMember("socket").getReturn() }
from DataFlow::CallCfgNode bindCall, DataFlow::Node addressArg, string hostname
where
call = socketBindCall() and
call.getArg(0).pointsTo(args) and
args.getItem(0) = getTextValue(address) and
address = allInterfaces()
select call.getNode(), "'" + address + "' binds a socket to all interfaces."
bindCall = socketInstance().getMember("bind").getACall() and
addressArg = bindCall.getArg(0) and
addressArg = vulnerableAddressTuple(hostname)
select bindCall.asExpr(), "'" + hostname + "' binds a socket to all interfaces."

View File

@@ -11,12 +11,25 @@
*/
import python
import semmle.python.web.flask.General
import semmle.python.dataflow.new.DataFlow
import semmle.python.ApiGraphs
import semmle.python.frameworks.Flask
from CallNode call, Value isTrue
/** Gets a reference to a truthy literal. */
private DataFlow::LocalSourceNode truthyLiteral(DataFlow::TypeTracker t) {
t.start() and
result.asExpr().(ImmutableLiteral).booleanValue() = true
or
exists(DataFlow::TypeTracker t2 | result = truthyLiteral(t2).track(t2, t))
}
/** Gets a reference to a truthy literal. */
DataFlow::Node truthyLiteral() { truthyLiteral(DataFlow::TypeTracker::end()).flowsTo(result) }
from DataFlow::CallCfgNode call, DataFlow::Node debugArg
where
call = theFlaskClass().declaredAttribute("run").(FunctionValue).getACall() and
call.getArgByName("debug").pointsTo(isTrue) and
isTrue.getDefiniteBooleanValue() = true
call.getFunction() = Flask::FlaskApp::instance().getMember("run").getAUse() and
debugArg in [call.getArg(2), call.getArgByName("debug")] and
debugArg = truthyLiteral()
select call,
"A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger."

View File

@@ -7,8 +7,8 @@
<p> A local variable is defined (by an assignment) but never used.
</p>
<include src="UnusedVariableNaming.qhelp" />
<include src="UnusedTuple.qhelp" />
<include src="UnusedVariableNaming.inc.qhelp" />
<include src="UnusedTuple.inc.qhelp" />
</overview>
<recommendation>

View File

@@ -8,8 +8,8 @@
and is not explicitly made public by inclusion in the <code>__all__</code> list.
</p>
<include src="UnusedVariableNaming.qhelp" />
<include src="UnusedTuple.qhelp" />
<include src="UnusedVariableNaming.inc.qhelp" />
<include src="UnusedTuple.inc.qhelp" />
</overview>
<recommendation>

View File

@@ -9,7 +9,7 @@
<p> A parameter is never used.
</p>
<include src="UnusedVariableNaming.qhelp" />
<include src="UnusedVariableNaming.inc.qhelp" />
</overview>
<recommendation>

View File

@@ -0,0 +1,33 @@
/**
* @name Binding a socket to all network interfaces
* @description Binding a socket to all interfaces opens it up to traffic from any IPv4 address
* and is therefore associated with security risks.
* @kind problem
*/
import python
Value aSocket() { result.getClass() = Value::named("socket.socket") }
CallNode socketBindCall() {
result = aSocket().attr("bind").(CallableValue).getACall() and major_version() = 3
or
result.getFunction().(AttrNode).getObject("bind").pointsTo(aSocket()) and
major_version() = 2
}
string allInterfaces() { result = "0.0.0.0" or result = "" }
Value getTextValue(string address) {
result = Value::forUnicode(address) and major_version() = 3
or
result = Value::forString(address) and major_version() = 2
}
from CallNode call, TupleValue args, string address
where
call = socketBindCall() and
call.getArg(0).pointsTo(args) and
args.getItem(0) = getTextValue(address) and
address = allInterfaces()
select call.getNode(), "'" + address + "' binds a socket to all interfaces."

View File

@@ -1,19 +1,7 @@
/**
* @name Uncontrolled data used in path expression
* @name OLD QUERY: Uncontrolled data used in path expression
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity error
* @sub-severity high
* @precision high
* @id py/path-injection
* @tags correctness
* security
* external/owasp/owasp-a1
* external/cwe/cwe-022
* external/cwe/cwe-023
* external/cwe/cwe-036
* external/cwe/cwe-073
* external/cwe/cwe-099
*/
import python

View File

@@ -1,17 +1,8 @@
/**
* @name Uncontrolled command line
* @name OLD QUERY: Uncontrolled command line
* @description Using externally controlled strings in a command line may allow a malicious
* user to change the meaning of the command.
* @kind path-problem
* @problem.severity error
* @sub-severity high
* @precision high
* @id py/command-line-injection
* @tags correctness
* security
* external/owasp/owasp-a1
* external/cwe/cwe-078
* external/cwe/cwe-088
*/
import python

View File

@@ -1,15 +1,8 @@
/**
* @name Reflected server-side cross-site scripting
* @name OLD QUERY: Reflected server-side cross-site scripting
* @description Writing user input directly to a web page
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @sub-severity high
* @precision high
* @id py/reflective-xss
* @tags security
* external/cwe/cwe-079
* external/cwe/cwe-116
*/
import python

View File

@@ -1,14 +1,8 @@
/**
* @name SQL query built from user-controlled sources
* @name OLD QUERY: SQL query built from user-controlled sources
* @description Building a SQL query from user-controlled sources is vulnerable to insertion of
* malicious SQL code by the user.
* @kind path-problem
* @problem.severity error
* @precision high
* @id py/sql-injection
* @tags security
* external/cwe/cwe-089
* external/owasp/owasp-a1
*/
import python

View File

@@ -3,15 +3,6 @@
* @description Interpreting unsanitized user input as code allows a malicious user arbitrary
* code execution.
* @kind path-problem
* @problem.severity error
* @sub-severity high
* @precision high
* @id py/code-injection
* @tags security
* external/owasp/owasp-a1
* external/cwe/cwe-094
* external/cwe/cwe-095
* external/cwe/cwe-116
*/
import python

View File

@@ -1,14 +1,7 @@
/**
* @name Deserializing untrusted input
* @name OLD QUERY: Deserializing untrusted input
* @description Deserializing user-controlled data may allow attackers to execute arbitrary code.
* @kind path-problem
* @id py/unsafe-deserialization
* @problem.severity error
* @sub-severity high
* @precision high
* @tags external/cwe/cwe-502
* security
* serialization
*/
import python

View File

@@ -1,14 +1,8 @@
/**
* @name URL redirection from remote source
* @name OLD QUERY: URL redirection from remote source
* @description URL redirection based on unvalidated user input
* may cause redirection to malicious web sites.
* @kind path-problem
* @problem.severity error
* @sub-severity low
* @id py/url-redirection
* @tags security
* external/cwe/cwe-601
* @precision high
*/
import python

View File

@@ -1,10 +1,7 @@
/**
* Provides classes for modeling cryptographic libraries.
*/
/*
* The following information is copied from `/semmlecode-javascript-queries/semmle/javascript/frameworks/CryptoLibraries.qll`
* which should be considered the definitive version (as of Feb 2018)
* Provides classes modeling cryptographic algorithms, separated into strong and weak variants.
*
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
*/
/**
@@ -13,6 +10,8 @@
* The names are normalized: upper-case, no spaces, dashes or underscores.
*
* The names are inspired by the names used in real world crypto libraries.
*
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
*/
private module AlgorithmNames {
predicate isStrongHashingAlgorithm(string name) {
@@ -81,14 +80,6 @@ private module AlgorithmNames {
}
predicate isWeakPasswordHashingAlgorithm(string name) { none() }
/**
* Normalizes `name`: upper-case, no spaces, dashes or underscores.
*
* All names of this module are in this normalized form.
*/
bindingset[name]
string normalizeName(string name) { result = name.toUpperCase().regexpReplaceAll("[-_ ]", "") }
}
private import AlgorithmNames
@@ -121,10 +112,19 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
string toString() { result = getName() }
/**
* Gets the name of the algorithm.
* Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores).
*/
abstract string getName();
/**
* Holds if the name of this algorithm matches `name` modulo case,
* white space, dashes, and underscores.
*/
bindingset[name]
predicate matchesName(string name) {
name.toUpperCase().regexpReplaceAll("[-_ ]", "") = getName()
}
/**
* Holds if this algorithm is weak.
*/

View File

@@ -216,6 +216,9 @@ module API {
*/
Node moduleImport(string m) { result = Impl::MkModuleImport(m) }
/** Gets a node corresponding to the built-in with the given name, if any. */
Node builtin(string n) { result = moduleImport("builtins").getMember(n) }
/**
* Provides the actual implementation of API graphs, cached for performance.
*
@@ -300,11 +303,18 @@ module API {
MkRoot() or
/** An abstract representative for imports of the module called `name`. */
MkModuleImport(string name) {
imports(_, name)
// Ignore the following module name for Python 2, as we alias `__builtin__` to `builtins` elsewhere
(name != "__builtin__" or major_version() = 3) and
(
imports(_, name)
or
// When we `import foo.bar.baz` we want to create API graph nodes also for the prefixes
// `foo` and `foo.bar`:
name = any(ImportExpr e | not e.isRelative()).getAnImportedModuleName()
)
or
// When we `import foo.bar.baz` we want to create API graph nodes also for the prefixes
// `foo` and `foo.bar`:
name = any(ImportExpr e | not e.isRelative()).getAnImportedModuleName()
// The `builtins` module should always be implicitly available
name = "builtins"
} or
/** A use of an API member at the node `nd`. */
MkUse(DataFlow::Node nd) { use(_, _, nd) }
@@ -339,6 +349,24 @@ module API {
)
}
private import semmle.python.types.Builtins as Builtins
/**
* Gets a data flow node that is likely to refer to a built-in with the name `name`.
*
* Currently this is an over-approximation, and does not account for things like overwriting a
* built-in with a different value.
*/
private DataFlow::Node likely_builtin(string name) {
result.asCfgNode() =
any(NameNode n |
n.isGlobal() and
n.isLoad() and
name = n.getId() and
name = any(Builtins::Builtin b).getName()
)
}
/**
* Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled
* `lbl` in the API graph.
@@ -369,6 +397,10 @@ module API {
ref.asExpr().(ClassExpr).getABase() = superclass.asExpr()
)
)
or
// Built-ins, treated as members of the module `builtins`
base = MkModuleImport("builtins") and
lbl = Label::member(any(string name | ref = likely_builtin(name)))
}
/**
@@ -381,6 +413,11 @@ module API {
imports(ref, name)
)
or
// Ensure the Python 2 `__builtin__` module gets the name of the Python 3 `builtins` module.
major_version() = 2 and
nd = MkModuleImport("builtins") and
imports(ref, "__builtin__")
or
nd = MkUse(ref)
}

View File

@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
)
}
private class AdditionalFlowStepSource extends Node {
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
}
pragma[noinline]
private predicate isAdditionalFlowStep(
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
) {
config.isAdditionalFlowStep(node1, node2) and
callable1 = node1.getEnclosingCallable()
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
simpleLocalFlowStep(node1, node2) and
(
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
exists(DataFlowCallable callable1 |
isAdditionalFlowStep(node1, node2, callable1, config) and
node2.getEnclosingCallable() != callable1 and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
@@ -598,7 +588,7 @@ private module Stage1 {
) {
exists(ReturnNodeExt ret |
throughFlowNodeCand(ret, config) and
callable = ret.getEnclosingCallable() and
callable = getNodeEnclosingCallable(ret) and
kind = ret.getKind()
)
}
@@ -611,7 +601,7 @@ private module Stage1 {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
getNodeEnclosingCallable(p) = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
not exists(int pos |
@@ -775,7 +765,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
private ApNil getApNil(Node node) { any() }
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -963,7 +953,7 @@ private module Stage2 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -982,7 +972,7 @@ private module Stage2 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1213,13 +1203,13 @@ private module Stage2 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -1345,7 +1335,7 @@ private module LocalFlowBigStep {
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
or
@@ -1394,7 +1384,9 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
@@ -1591,7 +1583,7 @@ private module Stage3 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1610,7 +1602,7 @@ private module Stage3 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1841,13 +1833,13 @@ private module Stage3 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2087,7 +2079,9 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
@@ -2132,7 +2126,7 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, node.getEnclosingCallable())
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
}
private predicate localStep(
@@ -2297,7 +2291,7 @@ private module Stage4 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2316,7 +2310,7 @@ private module Stage4 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -2547,13 +2541,13 @@ private module Stage4 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2587,7 +2581,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
n.getEnclosingCallable() = c
getNodeEnclosingCallable(n) = c
)
}
@@ -3116,7 +3110,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3402,14 +3396,14 @@ private module FlowExploration {
// flow out of a callable
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
c1 = node1.getEnclosingCallable() and
c2 = node2.getEnclosingCallable() and
c1 = getNodeEnclosingCallable(node1) and
c2 = getNodeEnclosingCallable(node2) and
c1 != c2
)
}
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
@@ -3417,7 +3411,7 @@ private module FlowExploration {
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
@@ -3446,13 +3440,13 @@ private module FlowExploration {
exists(Node n, Configuration config |
ce1 = TCallableSrc() and
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
ce2 = TCallable(getNodeEnclosingCallable(n), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
ce1 = TCallable(getNodeEnclosingCallable(n), config)
)
}
@@ -3583,7 +3577,7 @@ private module FlowExploration {
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
@@ -3600,7 +3594,7 @@ private module FlowExploration {
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
}
@@ -3659,7 +3653,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
/**
@@ -3667,7 +3661,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
private string ppAp() {

View File

@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
)
}
private class AdditionalFlowStepSource extends Node {
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
}
pragma[noinline]
private predicate isAdditionalFlowStep(
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
) {
config.isAdditionalFlowStep(node1, node2) and
callable1 = node1.getEnclosingCallable()
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
simpleLocalFlowStep(node1, node2) and
(
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
exists(DataFlowCallable callable1 |
isAdditionalFlowStep(node1, node2, callable1, config) and
node2.getEnclosingCallable() != callable1 and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
@@ -598,7 +588,7 @@ private module Stage1 {
) {
exists(ReturnNodeExt ret |
throughFlowNodeCand(ret, config) and
callable = ret.getEnclosingCallable() and
callable = getNodeEnclosingCallable(ret) and
kind = ret.getKind()
)
}
@@ -611,7 +601,7 @@ private module Stage1 {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
getNodeEnclosingCallable(p) = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
not exists(int pos |
@@ -775,7 +765,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
private ApNil getApNil(Node node) { any() }
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -963,7 +953,7 @@ private module Stage2 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -982,7 +972,7 @@ private module Stage2 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1213,13 +1203,13 @@ private module Stage2 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -1345,7 +1335,7 @@ private module LocalFlowBigStep {
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
or
@@ -1394,7 +1384,9 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
@@ -1591,7 +1583,7 @@ private module Stage3 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1610,7 +1602,7 @@ private module Stage3 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1841,13 +1833,13 @@ private module Stage3 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2087,7 +2079,9 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
@@ -2132,7 +2126,7 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, node.getEnclosingCallable())
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
}
private predicate localStep(
@@ -2297,7 +2291,7 @@ private module Stage4 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2316,7 +2310,7 @@ private module Stage4 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -2547,13 +2541,13 @@ private module Stage4 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2587,7 +2581,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
n.getEnclosingCallable() = c
getNodeEnclosingCallable(n) = c
)
}
@@ -3116,7 +3110,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3402,14 +3396,14 @@ private module FlowExploration {
// flow out of a callable
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
c1 = node1.getEnclosingCallable() and
c2 = node2.getEnclosingCallable() and
c1 = getNodeEnclosingCallable(node1) and
c2 = getNodeEnclosingCallable(node2) and
c1 != c2
)
}
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
@@ -3417,7 +3411,7 @@ private module FlowExploration {
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
@@ -3446,13 +3440,13 @@ private module FlowExploration {
exists(Node n, Configuration config |
ce1 = TCallableSrc() and
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
ce2 = TCallable(getNodeEnclosingCallable(n), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
ce1 = TCallable(getNodeEnclosingCallable(n), config)
)
}
@@ -3583,7 +3577,7 @@ private module FlowExploration {
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
@@ -3600,7 +3594,7 @@ private module FlowExploration {
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
}
@@ -3659,7 +3653,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
/**
@@ -3667,7 +3661,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
private string ppAp() {

View File

@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
)
}
private class AdditionalFlowStepSource extends Node {
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
}
pragma[noinline]
private predicate isAdditionalFlowStep(
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
) {
config.isAdditionalFlowStep(node1, node2) and
callable1 = node1.getEnclosingCallable()
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
simpleLocalFlowStep(node1, node2) and
(
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
exists(DataFlowCallable callable1 |
isAdditionalFlowStep(node1, node2, callable1, config) and
node2.getEnclosingCallable() != callable1 and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
@@ -598,7 +588,7 @@ private module Stage1 {
) {
exists(ReturnNodeExt ret |
throughFlowNodeCand(ret, config) and
callable = ret.getEnclosingCallable() and
callable = getNodeEnclosingCallable(ret) and
kind = ret.getKind()
)
}
@@ -611,7 +601,7 @@ private module Stage1 {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
getNodeEnclosingCallable(p) = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
not exists(int pos |
@@ -775,7 +765,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
private ApNil getApNil(Node node) { any() }
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -963,7 +953,7 @@ private module Stage2 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -982,7 +972,7 @@ private module Stage2 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1213,13 +1203,13 @@ private module Stage2 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -1345,7 +1335,7 @@ private module LocalFlowBigStep {
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
or
@@ -1394,7 +1384,9 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
@@ -1591,7 +1583,7 @@ private module Stage3 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1610,7 +1602,7 @@ private module Stage3 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1841,13 +1833,13 @@ private module Stage3 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2087,7 +2079,9 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
@@ -2132,7 +2126,7 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, node.getEnclosingCallable())
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
}
private predicate localStep(
@@ -2297,7 +2291,7 @@ private module Stage4 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2316,7 +2310,7 @@ private module Stage4 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -2547,13 +2541,13 @@ private module Stage4 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2587,7 +2581,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
n.getEnclosingCallable() = c
getNodeEnclosingCallable(n) = c
)
}
@@ -3116,7 +3110,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3402,14 +3396,14 @@ private module FlowExploration {
// flow out of a callable
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
c1 = node1.getEnclosingCallable() and
c2 = node2.getEnclosingCallable() and
c1 = getNodeEnclosingCallable(node1) and
c2 = getNodeEnclosingCallable(node2) and
c1 != c2
)
}
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
@@ -3417,7 +3411,7 @@ private module FlowExploration {
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
@@ -3446,13 +3440,13 @@ private module FlowExploration {
exists(Node n, Configuration config |
ce1 = TCallableSrc() and
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
ce2 = TCallable(getNodeEnclosingCallable(n), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
ce1 = TCallable(getNodeEnclosingCallable(n), config)
)
}
@@ -3583,7 +3577,7 @@ private module FlowExploration {
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
@@ -3600,7 +3594,7 @@ private module FlowExploration {
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
}
@@ -3659,7 +3653,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
/**
@@ -3667,7 +3661,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
private string ppAp() {

View File

@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
)
}
private class AdditionalFlowStepSource extends Node {
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
}
pragma[noinline]
private predicate isAdditionalFlowStep(
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
) {
config.isAdditionalFlowStep(node1, node2) and
callable1 = node1.getEnclosingCallable()
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
simpleLocalFlowStep(node1, node2) and
(
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` does not jump between callables.
*/
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
* Holds if the additional step from `node1` to `node2` jumps between callables.
*/
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
exists(DataFlowCallable callable1 |
isAdditionalFlowStep(node1, node2, callable1, config) and
node2.getEnclosingCallable() != callable1 and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
config.isAdditionalFlowStep(node1, node2) and
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
@@ -598,7 +588,7 @@ private module Stage1 {
) {
exists(ReturnNodeExt ret |
throughFlowNodeCand(ret, config) and
callable = ret.getEnclosingCallable() and
callable = getNodeEnclosingCallable(ret) and
kind = ret.getKind()
)
}
@@ -611,7 +601,7 @@ private module Stage1 {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
p.getEnclosingCallable() = c and
getNodeEnclosingCallable(p) = c and
exists(ap) and
// we don't expect a parameter to return stored in itself
not exists(int pos |
@@ -775,7 +765,7 @@ private module Stage2 {
bindingset[result, ap]
private ApApprox getApprox(Ap ap) { any() }
private ApNil getApNil(Node node) { any() }
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
@@ -963,7 +953,7 @@ private module Stage2 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -982,7 +972,7 @@ private module Stage2 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1213,13 +1203,13 @@ private module Stage2 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -1345,7 +1335,7 @@ private module LocalFlowBigStep {
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, unbind(config))
or
@@ -1394,7 +1384,9 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
@@ -1591,7 +1583,7 @@ private module Stage3 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1610,7 +1602,7 @@ private module Stage3 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -1841,13 +1833,13 @@ private module Stage3 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2087,7 +2079,9 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
}
bindingset[tc, tail]
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
@@ -2132,7 +2126,7 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
localFlowEntry(node, config) and
result = getLocalCallContext(cc, node.getEnclosingCallable())
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
}
private predicate localStep(
@@ -2297,7 +2291,7 @@ private module Stage4 {
exists(ArgumentNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2316,7 +2310,7 @@ private module Stage4 {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
inner = getNodeEnclosingCallable(ret) and
checkCallContextReturn(innercc, inner, call) and
ccOut = getCallContextReturn(inner, call)
|
@@ -2547,13 +2541,13 @@ private module Stage4 {
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = p.getEnclosingCallable()
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = ret.getEnclosingCallable() and
c = getNodeEnclosingCallable(ret) and
revFlow(ret, true, apSome(_), ap0, config) and
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
kind = ret.getKind() and
@@ -2587,7 +2581,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
Stage4::parameterMayFlowThrough(_, c, apa, _) and
Stage4::revFlow(n, true, _, apa0, config) and
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
n.getEnclosingCallable() = c
getNodeEnclosingCallable(n) = c
)
}
@@ -3116,7 +3110,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3402,14 +3396,14 @@ private module FlowExploration {
// flow out of a callable
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
c1 = node1.getEnclosingCallable() and
c2 = node2.getEnclosingCallable() and
c1 = getNodeEnclosingCallable(node1) and
c2 = getNodeEnclosingCallable(node2) and
c1 != c2
)
}
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
@@ -3417,7 +3411,7 @@ private module FlowExploration {
}
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
or
exists(DataFlowCallable mid |
interestingCallableSink(mid, config) and callableStep(c, mid, config)
@@ -3446,13 +3440,13 @@ private module FlowExploration {
exists(Node n, Configuration config |
ce1 = TCallableSrc() and
config.isSource(n) and
ce2 = TCallable(n.getEnclosingCallable(), config)
ce2 = TCallable(getNodeEnclosingCallable(n), config)
)
or
exists(Node n, Configuration config |
ce2 = TCallableSink() and
config.isSink(n) and
ce1 = TCallable(n.getEnclosingCallable(), config)
ce1 = TCallable(getNodeEnclosingCallable(n), config)
)
}
@@ -3583,7 +3577,7 @@ private module FlowExploration {
exists(config.explorationLimit())
or
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
} or
TPartialPathNodeRev(
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
@@ -3600,7 +3594,7 @@ private module FlowExploration {
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
}
@@ -3659,7 +3653,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSourceDistance() {
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
/**
@@ -3667,7 +3661,7 @@ private module FlowExploration {
* of interprocedural steps.
*/
int getSinkDistance() {
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
}
private string ppAp() {

View File

@@ -415,6 +415,30 @@ private module Cached {
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
}
/**
* Holds if data can flow from `fromNode` to `toNode` because they are the post-update
* nodes of some function output and input respectively, where the output and input
* are aliases. A typical example is a function returning `this`, implementing a fluent
* interface.
*/
cached
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode()
|
exists(DataFlowCall c |
// Does the language-specific simpleLocalFlowStep already model flow
// from function input to output?
fromPre = getAnOutNode(c, _) and
toPre.(ArgumentNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre)
)
or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
)
}
/**
* Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -423,7 +447,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call)
or
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
}
cached
@@ -568,7 +592,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | p.getEnclosingCallable() = callable)
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
}
override predicate matchesCall(DataFlowCall call) { any() }
@@ -613,7 +637,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
}
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
}
/**
@@ -722,9 +746,22 @@ class ReturnPosition extends TReturnPosition0 {
string toString() { result = "[" + kind + "] " + c }
}
/**
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
* predicate ensures that joins go from `n` to the result instead of the other
* way around.
*/
pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) {
exists(Node n0 |
pragma[only_bind_into](n0) = n and
pragma[only_bind_into](result) = n0.getEnclosingCallable()
)
}
pragma[noinline]
private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) {
result = ret.getEnclosingCallable()
result = getNodeEnclosingCallable(ret)
}
pragma[noinline]

View File

@@ -819,7 +819,15 @@ class DataFlowType extends TDataFlowType {
/** A node that performs a type cast. */
class CastNode extends Node {
CastNode() { none() }
// We include read- and store steps here to force them to be
// shown in path explanations.
// This hack is necessary, because we have included some of these
// steps as default taint steps, making them be suppressed in path
// explanations.
// We should revert this once, we can remove this steps from the
// default taint steps; this should be possible once we have
// implemented flow summaries and recursive content.
CastNode() { readStep(_, _, this) or storeStep(_, _, this) }
}
/**

View File

@@ -2074,7 +2074,11 @@ private module Django {
// TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
// points-to and `.lookup`, which would handle `post = my_post_handler` inside class def
result = this.getAMethod() and
result.getName() = HTTP::httpVerbLower()
(
result.getName() = HTTP::httpVerbLower()
or
result.getName() = "get_redirect_url"
)
}
/**
@@ -2124,6 +2128,8 @@ private module Django {
/**
* A function that is a django route handler, meaning it handles incoming requests
* with the django framework.
*
* Most functions take a django HttpRequest as a parameter (but not all).
*/
private class DjangoRouteHandler extends Function {
DjangoRouteHandler() {
@@ -2132,6 +2138,12 @@ private module Django {
any(DjangoViewClass vc).getARequestHandler() = this
}
/**
* Gets the index of the parameter where the first routed parameter can be passed --
* that is, the one just after any possible `self` or HttpRequest parameters.
*/
int getFirstPossibleRoutedParamIndex() { result = 1 + this.getRequestParamIndex() }
/** Gets the index of the request parameter. */
int getRequestParamIndex() {
not this.isMethod() and
@@ -2145,6 +2157,26 @@ private module Django {
Parameter getRequestParam() { result = this.getArg(this.getRequestParamIndex()) }
}
/**
* A method named `get_redirect_url` on a django view class.
*
* See https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#django.views.generic.base.RedirectView.get_redirect_url
*
* Note: this function only does something on a subclass of `RedirectView`, but since
* classes can be considered django view classes without us knowing their super-classes,
* we need to consider _any_ django view class. I don't expect any problems to come from this.
*/
private class GetRedirectUrlFunction extends DjangoRouteHandler {
GetRedirectUrlFunction() {
this.getName() = "get_redirect_url" and
any(DjangoViewClass vc).getARequestHandler() = this
}
override int getFirstPossibleRoutedParamIndex() { result = 1 }
override int getRequestParamIndex() { none() }
}
/** A data-flow node that sets up a route on a server, using the django framework. */
abstract private class DjangoRouteSetup extends HTTP::Server::RouteSetup::Range, DataFlow::CfgNode {
/** Gets the data-flow node that is used as the argument for the view handler. */
@@ -2175,7 +2207,7 @@ private module Django {
// parameter. This should give us more RemoteFlowSources but could also lead to
// more FPs. If this turns out to be the wrong tradeoff, we can always change our mind.
result in [this.getArg(_), this.getArgByName(_)] and
not result = any(int i | i <= this.getRequestParamIndex() | this.getArg(i))
not result = any(int i | i < this.getFirstPossibleRoutedParamIndex() | this.getArg(i))
}
override string getFramework() { result = "Django" }
@@ -2215,7 +2247,8 @@ private module Django {
exists(DjangoRouteHandler routeHandler | routeHandler = this.getARequestHandler() |
not exists(this.getUrlPattern()) and
result in [routeHandler.getArg(_), routeHandler.getArgByName(_)] and
not result = any(int i | i <= routeHandler.getRequestParamIndex() | routeHandler.getArg(i))
not result =
any(int i | i < routeHandler.getFirstPossibleRoutedParamIndex() | routeHandler.getArg(i))
)
or
exists(string name |
@@ -2237,7 +2270,8 @@ private module Django {
exists(DjangoRouteHandler routeHandler | routeHandler = this.getARequestHandler() |
not exists(this.getUrlPattern()) and
result in [routeHandler.getArg(_), routeHandler.getArgByName(_)] and
not result = any(int i | i <= routeHandler.getRequestParamIndex() | routeHandler.getArg(i))
not result =
any(int i | i < routeHandler.getFirstPossibleRoutedParamIndex() | routeHandler.getArg(i))
)
or
exists(DjangoRouteHandler routeHandler, DjangoRouteRegex regex |
@@ -2249,7 +2283,9 @@ private module Django {
not exists(regex.getGroupName(_, _)) and
// first group will have group number 1
result =
routeHandler.getArg(routeHandler.getRequestParamIndex() + regex.getGroupNumber(_, _))
routeHandler
.getArg(routeHandler.getFirstPossibleRoutedParamIndex() - 1 +
regex.getGroupNumber(_, _))
or
result = routeHandler.getArgByName(regex.getGroupName(_, _))
)
@@ -2445,4 +2481,31 @@ private module Django {
override string getMimetypeDefault() { none() }
}
// ---------------------------------------------------------------------------
// RedirectView handling
// ---------------------------------------------------------------------------
/**
* A return from a method named `get_redirect_url` on a django view class.
*
* Note that in reality, this only does something on a subclass of `RedirectView` --
* but until API graphs makes this easy to model, I took a shortcut in modeling
* preciseness.
*
* See https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#redirectview
*/
private class DjangoRedirectViewGetRedirectUrlReturn extends HTTP::Server::HttpRedirectResponse::Range,
DataFlow::CfgNode {
DjangoRedirectViewGetRedirectUrlReturn() {
node = any(GetRedirectUrlFunction f).getAReturnValueFlowNode()
}
override DataFlow::Node getRedirectLocation() { result = this }
override DataFlow::Node getBody() { none() }
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
override string getMimetypeDefault() { none() }
}
}

View File

@@ -351,7 +351,8 @@ module Flask {
exists(string method_name | method_name in ["get_data", "get_json"] |
// Method access
nodeFrom = request().getAUse() and
nodeTo = request().getMember(method_name).getAnImmediateUse()
nodeTo.(DataFlow::AttrRead).getObject() = nodeFrom and
nodeTo.(DataFlow::AttrRead).getAttributeName() = method_name
or
// Method call
nodeFrom = request().getMember(method_name).getAUse() and

View File

@@ -1,34 +1,39 @@
import python
import semmle.python.objects.ObjectInternal
deprecated import semmle.python.objects.ObjectInternal as OI
private import semmle.python.ApiGraphs
private predicate re_module_function(string name, int flags) {
name = "compile" and flags = 1
/**
* Gets the positional argument index containing the regular expression flags for the member of the
* `re` module with the name `name`.
*/
private int re_member_flags_arg(string name) {
name = "compile" and result = 1
or
name = "search" and flags = 2
name = "search" and result = 2
or
name = "match" and flags = 2
name = "match" and result = 2
or
name = "split" and flags = 3
name = "split" and result = 3
or
name = "findall" and flags = 2
name = "findall" and result = 2
or
name = "finditer" and flags = 2
name = "finditer" and result = 2
or
name = "sub" and flags = 4
name = "sub" and result = 4
or
name = "subn" and flags = 4
name = "subn" and result = 4
}
/**
* Gets the names and corresponding values of attributes of the `re` module that are likely to be
* Gets the names and corresponding API nodes of members of the `re` module that are likely to be
* methods taking regular expressions as arguments.
*
* This is a helper predicate that fixes a bad join order, and should not be inlined without checking
* that this is safe.
*/
pragma[nomagic]
private Value relevant_re_attr(string name) {
result = Module::named("re").attr(name) and
private API::Node relevant_re_member(string name) {
result = API::moduleImport("re").getMember(name) and
name != "escape"
}
@@ -39,24 +44,78 @@ private Value relevant_re_attr(string name) {
predicate used_as_regex(Expr s, string mode) {
(s instanceof Bytes or s instanceof Unicode) and
/* Call to re.xxx(regex, ... [mode]) */
exists(CallNode call, string name |
call.getArg(0).pointsTo(_, _, s.getAFlowNode()) and
call.getFunction().pointsTo(relevant_re_attr(name))
exists(DataFlow::CallCfgNode call, string name |
call.getArg(0).asExpr() = s and
call = relevant_re_member(name).getACall()
|
mode = "None"
or
exists(Value obj | mode = mode_from_mode_object(obj) |
exists(int flags_arg |
re_module_function(name, flags_arg) and
call.getArg(flags_arg).pointsTo(obj)
)
or
call.getArgByName("flags").pointsTo(obj)
mode = mode_from_node([call.getArg(re_member_flags_arg(name)), call.getArgByName("flags")])
)
}
/**
* Gets the canonical name for the API graph node corresponding to the `re` flag `flag`. For flags
* that have multiple names, we pick the long-form name as a canonical representative.
*/
private string canonical_name(API::Node flag) {
result in ["ASCII", "IGNORECASE", "LOCALE", "UNICODE", "MULTILINE", "TEMPLATE"] and
flag = API::moduleImport("re").getMember([result, result.prefix(1)])
or
flag = API::moduleImport("re").getMember(["DOTALL", "S"]) and result = "DOTALL"
or
flag = API::moduleImport("re").getMember(["VERBOSE", "X"]) and result = "VERBOSE"
}
/**
* A type tracker for regular expression flag names. Holds if the result is a node that may refer
* to the `re` flag with the canonical name `flag_name`
*/
private DataFlow::LocalSourceNode re_flag_tracker(string flag_name, DataFlow::TypeTracker t) {
t.start() and
exists(API::Node flag | flag_name = canonical_name(flag) and result = flag.getAUse())
or
exists(BinaryExprNode binop, DataFlow::Node operand |
operand.getALocalSource() = re_flag_tracker(flag_name, t.continue()) and
operand.asCfgNode() = binop.getAnOperand() and
(binop.getOp() instanceof BitOr or binop.getOp() instanceof Add) and
result.asCfgNode() = binop
)
or
// Due to bad performance when using normal setup with `re_flag_tracker(t2, attr_name).track(t2, t)`
// we have inlined that code and forced a join
exists(DataFlow::TypeTracker t2 |
exists(DataFlow::StepSummary summary |
re_flag_tracker_first_join(t2, flag_name, result, summary) and
t = t2.append(summary)
)
)
}
string mode_from_mode_object(Value obj) {
pragma[nomagic]
private predicate re_flag_tracker_first_join(
DataFlow::TypeTracker t2, string flag_name, DataFlow::Node res, DataFlow::StepSummary summary
) {
DataFlow::StepSummary::step(re_flag_tracker(flag_name, t2), res, summary)
}
/**
* A type tracker for regular expression flag names. Holds if the result is a node that may refer
* to the `re` flag with the canonical name `flag_name`
*/
private DataFlow::Node re_flag_tracker(string flag_name) {
re_flag_tracker(flag_name, DataFlow::TypeTracker::end()).flowsTo(result)
}
/** Gets a regular expression mode flag associated with the given data flow node. */
string mode_from_node(DataFlow::Node node) { node = re_flag_tracker(result) }
/**
* DEPRECATED 2021-02-24 -- use `mode_from_node` instead.
*
* Gets a regular expression mode flag associated with the given value.
*/
deprecated string mode_from_mode_object(Value obj) {
(
result = "DEBUG" or
result = "IGNORECASE" or
@@ -67,8 +126,8 @@ string mode_from_mode_object(Value obj) {
result = "VERBOSE"
) and
exists(int flag |
flag = Value::named("sre_constants.SRE_FLAG_" + result).(ObjectInternal).intValue() and
obj.(ObjectInternal).intValue().bitAnd(flag) = flag
flag = Value::named("sre_constants.SRE_FLAG_" + result).(OI::ObjectInternal).intValue() and
obj.(OI::ObjectInternal).intValue().bitAnd(flag) = flag
)
}