mirror of
https://github.com/github/codeql.git
synced 2026-05-05 05:35:13 +02:00
Merge branch 'main' into redundantImport
This commit is contained in:
@@ -1,3 +1,17 @@
|
||||
## 0.1.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||
|
||||
### New Features
|
||||
|
||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||
|
||||
## 0.0.13
|
||||
|
||||
## 0.0.12
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||
4
cpp/ql/lib/change-notes/2022-04-22-no-size-array.md
Normal file
4
cpp/ql/lib/change-notes/2022-04-22-no-size-array.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
The signature of `allowImplicitRead` on `DataFlow::Configuration` and `TaintTracking::Configuration` has changed from `allowImplicitRead(DataFlow::Node node, DataFlow::Content c)` to `allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c)`.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||
13
cpp/ql/lib/change-notes/released/0.1.0.md
Normal file
13
cpp/ql/lib/change-notes/released/0.1.0.md
Normal file
@@ -0,0 +1,13 @@
|
||||
## 0.1.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||
|
||||
### New Features
|
||||
|
||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.13
|
||||
lastReleaseVersion: 0.1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.1.0-dev
|
||||
version: 0.1.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -10,11 +10,18 @@ import semmle.code.cpp.dataflow.DataFlow
|
||||
* char data[1]; // v
|
||||
* };
|
||||
* ```
|
||||
* This requires that `v` is an array of size 0 or 1.
|
||||
* or
|
||||
* ```
|
||||
* struct myStruct { // c
|
||||
* int amount;
|
||||
* char data[]; // v
|
||||
* };
|
||||
* ```
|
||||
* This requires that `v` is an array of size 0 or 1, or that the array has no size.
|
||||
*/
|
||||
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||
c = v.getDeclaringType() and
|
||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
||||
exists(ArrayType t | t = v.getUnspecifiedType() | not t.getArraySize() > 1)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,13 +47,18 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
result = why.(Expr).getType().(ArrayType).getSize() and
|
||||
not exists(bufferVar.getUnspecifiedType().(ArrayType).getSize())
|
||||
or
|
||||
exists(Class parentClass, VariableAccess parentPtr |
|
||||
exists(Class parentClass, VariableAccess parentPtr, int bufferSize |
|
||||
// buffer is the parentPtr->bufferVar of a 'variable size struct'
|
||||
memberMayBeVarSize(parentClass, bufferVar) and
|
||||
why = bufferVar and
|
||||
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
|
||||
(
|
||||
if exists(bufferVar.getType().getSize())
|
||||
then bufferSize = bufferVar.getType().getSize()
|
||||
else bufferSize = 0
|
||||
) and
|
||||
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
||||
)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -326,7 +326,7 @@ private module Cached {
|
||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||
|
||||
cached
|
||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
@@ -373,7 +373,7 @@ private module Cached {
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
read(_, _, n)
|
||||
readSet(_, _, n)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -469,7 +469,7 @@ private module Cached {
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, false) and
|
||||
read(mid, _, node) and
|
||||
readSet(mid, _, node) and
|
||||
read = true
|
||||
)
|
||||
or
|
||||
@@ -657,8 +657,10 @@ private module Cached {
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*
|
||||
* This predicate is exposed for testing only.
|
||||
*/
|
||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
||||
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
@@ -781,28 +783,30 @@ private module Cached {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
cached
|
||||
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
exists(ContentSet cs | c = cs.getAStoreContent() |
|
||||
storeStep(node1, cs, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
read(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
|
||||
or
|
||||
readSet(n2, cs, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||
* `f`.
|
||||
@@ -932,16 +936,16 @@ class CastingNode extends Node {
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||
) {
|
||||
read(n1, c, n2) and
|
||||
readSet(n1, c, n2) and
|
||||
container = getNodeDataFlowType(n1) and
|
||||
content = getNodeDataFlowType(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
TReadStepTypesNone() or
|
||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
||||
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||
readStepWithTypes(_, container, c, _, content)
|
||||
}
|
||||
|
||||
@@ -950,7 +954,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
||||
|
||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||
|
||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
|
||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||
|
||||
@@ -1325,8 +1329,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -821,6 +821,34 @@ private class CollectionContent extends Content, TCollectionContent {
|
||||
override string toString() { result = "<element>" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity that represents a set of `Content`s.
|
||||
*
|
||||
* The set may be interpreted differently depending on whether it is
|
||||
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||
*/
|
||||
class ContentSet instanceof Content {
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
Content getAStoreContent() { result = this }
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
Content getAReadContent() { result = this }
|
||||
|
||||
/** Gets a textual representation of this content set. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A guard that validates some expression.
|
||||
*
|
||||
|
||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -116,7 +116,7 @@ abstract class Configuration extends string {
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
@@ -485,8 +485,9 @@ private predicate additionalJumpStateStep(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
read(node1.asNode(), c, node2.asNode()) and
|
||||
pragma[nomagic]
|
||||
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||
readSet(node1.asNode(), c, node2.asNode()) and
|
||||
stepFilter(node1, node2, config)
|
||||
or
|
||||
exists(Node n |
|
||||
@@ -496,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
readSet(node1, cs, node2, config) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
// inline to reduce fan-out via `getAReadContent`
|
||||
pragma[inline]
|
||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||
exists(ContentSet cs |
|
||||
clearsContentCached(n.asNode(), cs) and
|
||||
c = cs.getAReadContent()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
@@ -573,9 +593,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(Content c |
|
||||
fwdFlowRead(c, node, cc, config) and
|
||||
fwdFlowConsCand(c, config)
|
||||
exists(ContentSet c |
|
||||
fwdFlowReadSet(c, node, cc, config) and
|
||||
fwdFlowConsCandSet(c, _, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -599,10 +619,10 @@ private module Stage1 {
|
||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||
exists(NodeEx mid |
|
||||
fwdFlow(mid, cc, config) and
|
||||
read(mid, c, node, config)
|
||||
readSet(mid, c, node, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -620,6 +640,16 @@ private module Stage1 {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||
* into `c`, in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||
fwdFlowConsCand(c, config) and
|
||||
c = cs.getAReadContent()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||
exists(RetNodeEx ret |
|
||||
@@ -712,9 +742,9 @@ private module Stage1 {
|
||||
)
|
||||
or
|
||||
// read
|
||||
exists(NodeEx mid, Content c |
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
exists(NodeEx mid, ContentSet c |
|
||||
readSet(node, c, mid, config) and
|
||||
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
@@ -740,10 +770,10 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid, config) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
readSet(node, cs, mid, config) and
|
||||
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -762,6 +792,7 @@ private module Stage1 {
|
||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
@@ -860,9 +891,9 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config))
|
||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -872,7 +903,10 @@ private module Stage1 {
|
||||
predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
||||
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||
exists(state) and
|
||||
exists(returnAp) and
|
||||
exists(ap)
|
||||
}
|
||||
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
@@ -1149,7 +1183,7 @@ private module Stage2 {
|
||||
|
||||
bindingset[node, state, ap, config]
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
PrevStage::revFlowState(state, config) and
|
||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state, config)
|
||||
}
|
||||
@@ -1574,7 +1608,7 @@ private module Stage2 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -1729,9 +1763,9 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
Stage2::readStepCand(_, _, node, config)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
@@ -1752,8 +1786,8 @@ private module LocalFlowBigStep {
|
||||
additionalJumpStep(node, next, config) or
|
||||
flowIntoCallNodeCand1(_, node, next, config) or
|
||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||
store(node, _, next, _, config) or
|
||||
read(node, _, next, config)
|
||||
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||
Stage2::readStepCand(node, _, next, config)
|
||||
)
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
@@ -1926,7 +1960,24 @@ private module Stage3 {
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||
PrevStage::revFlow(node, config) and
|
||||
clearsContentCached(node.asNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||
exists(ContentSet cs |
|
||||
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||
c = cs.getAReadContent() and
|
||||
clearSet(node, cs, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||
clearContent(node, ap.getHead().getContent(), config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||
@@ -1935,7 +1986,7 @@ private module Stage3 {
|
||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
exists(state) and
|
||||
exists(config) and
|
||||
not clear(node, ap) and
|
||||
not clear(node, ap, config) and
|
||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||
}
|
||||
|
||||
@@ -2363,7 +2414,7 @@ private module Stage3 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -3190,7 +3241,7 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
exists(Ap ap2, Content c |
|
||||
store(node1, tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||
revFlowConsCand(ap2, c, ap1, config)
|
||||
)
|
||||
@@ -4202,7 +4253,7 @@ private module Subpaths {
|
||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||
store(n1, _, n2, _, _) or
|
||||
read(n1, _, n2, _)
|
||||
readSet(n1, _, n2, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4557,7 +4608,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
@@ -4573,7 +4624,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not stateBarrier(node, state, config) and
|
||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -326,7 +326,7 @@ private module Cached {
|
||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||
|
||||
cached
|
||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
@@ -373,7 +373,7 @@ private module Cached {
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
read(_, _, n)
|
||||
readSet(_, _, n)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -469,7 +469,7 @@ private module Cached {
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, false) and
|
||||
read(mid, _, node) and
|
||||
readSet(mid, _, node) and
|
||||
read = true
|
||||
)
|
||||
or
|
||||
@@ -657,8 +657,10 @@ private module Cached {
|
||||
* Holds if `arg` flows to `out` through a call using only
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*
|
||||
* This predicate is exposed for testing only.
|
||||
*/
|
||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
||||
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
@@ -781,28 +783,30 @@ private module Cached {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
cached
|
||||
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
private predicate store(
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
exists(ContentSet cs | c = cs.getAStoreContent() |
|
||||
storeStep(node1, cs, node2) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
read(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
|
||||
or
|
||||
readSet(n2, cs, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||
* `f`.
|
||||
@@ -932,16 +936,16 @@ class CastingNode extends Node {
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||
) {
|
||||
read(n1, c, n2) and
|
||||
readSet(n1, c, n2) and
|
||||
container = getNodeDataFlowType(n1) and
|
||||
content = getNodeDataFlowType(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
TReadStepTypesNone() or
|
||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
||||
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||
readStepWithTypes(_, container, c, _, content)
|
||||
}
|
||||
|
||||
@@ -950,7 +954,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
||||
|
||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||
|
||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||
|
||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||
|
||||
@@ -1325,8 +1329,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -1063,6 +1063,34 @@ private class CollectionContent extends Content, TCollectionContent {
|
||||
override string toString() { result = "<element>" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity that represents a set of `Content`s.
|
||||
*
|
||||
* The set may be interpreted differently depending on whether it is
|
||||
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||
*/
|
||||
class ContentSet instanceof Content {
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
Content getAStoreContent() { result = this }
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
Content getAReadContent() { result = this }
|
||||
|
||||
/** Gets a textual representation of this content set. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A guard that validates some instruction.
|
||||
*
|
||||
|
||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ private predicate isOpaqueType(Type type) {
|
||||
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
||||
*/
|
||||
predicate hasOpaqueType(Type tag, int byteSize) {
|
||||
isOpaqueType(tag) and byteSize = getTypeSize(tag)
|
||||
isOpaqueType(tag) and byteSize = getTypeSize(tag.getUnspecifiedType())
|
||||
or
|
||||
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
||||
}
|
||||
@@ -153,17 +153,18 @@ private IRType getIRTypeForPRValue(Type type) {
|
||||
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
||||
isOpaqueType(unspecifiedType) and
|
||||
exists(IROpaqueType opaqueType | opaqueType = result |
|
||||
opaqueType.getByteSize() = getTypeSize(type) and
|
||||
opaqueType.getByteSize() = getTypeSize(unspecifiedType) and
|
||||
opaqueType.getTag() = unspecifiedType
|
||||
)
|
||||
or
|
||||
unspecifiedType instanceof BoolType and result.(IRBooleanType).getByteSize() = type.getSize()
|
||||
unspecifiedType instanceof BoolType and
|
||||
result.(IRBooleanType).getByteSize() = unspecifiedType.getSize()
|
||||
or
|
||||
isSignedIntegerType(unspecifiedType) and
|
||||
result.(IRSignedIntegerType).getByteSize() = type.getSize()
|
||||
result.(IRSignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||
or
|
||||
isUnsignedIntegerType(unspecifiedType) and
|
||||
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
|
||||
result.(IRUnsignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||
or
|
||||
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
||||
floatType = unspecifiedType and
|
||||
@@ -173,7 +174,8 @@ private IRType getIRTypeForPRValue(Type type) {
|
||||
irFloatType.getDomain() = floatType.getDomain()
|
||||
)
|
||||
or
|
||||
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
|
||||
isPointerIshType(unspecifiedType) and
|
||||
result.(IRAddressType).getByteSize() = getTypeSize(unspecifiedType)
|
||||
or
|
||||
unspecifiedType instanceof FunctionPointerIshType and
|
||||
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
||||
|
||||
@@ -42,10 +42,13 @@ private class MallocAllocationFunction extends AllocationFunction {
|
||||
this.hasGlobalName([
|
||||
// --- Windows Memory Management for Windows Drivers
|
||||
"ExAllocatePool", // ExAllocatePool(type, size)
|
||||
"ExAllocatePool2", // ExAllocatePool2(flags, size, tag)
|
||||
"ExAllocatePool3", // ExAllocatePool3(flags, size, tag, extparams, extparamscount)
|
||||
"ExAllocatePoolWithTag", // ExAllocatePool(type, size, tag)
|
||||
"ExAllocatePoolWithTagPriority", // ExAllocatePoolWithTagPriority(type, size, tag, priority)
|
||||
"ExAllocatePoolWithQuota", // ExAllocatePoolWithQuota(type, size)
|
||||
"ExAllocatePoolWithQuotaTag", // ExAllocatePoolWithQuotaTag(type, size, tag)
|
||||
"ExAllocatePoolZero", // ExAllocatePoolZero(type, size, tag)
|
||||
"IoAllocateMdl", // IoAllocateMdl(address, size, flag, flag, irp)
|
||||
"IoAllocateErrorLogEntry", // IoAllocateErrorLogEntry(object, size)
|
||||
// --- Windows Global / Local legacy allocation
|
||||
|
||||
Reference in New Issue
Block a user