mirror of
https://github.com/github/codeql.git
synced 2025-12-21 19:26:31 +01:00
Merge branch 'main' into pyMaD
This commit is contained in:
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
@@ -11,7 +11,7 @@ Java:
|
|||||||
- change-notes/**/*java.*
|
- change-notes/**/*java.*
|
||||||
|
|
||||||
JS:
|
JS:
|
||||||
- javascript/**/*
|
- any: [ 'javascript/**/*', '!javascript/ql/experimental/adaptivethreatmodeling/**/*' ]
|
||||||
- change-notes/**/*javascript*
|
- change-notes/**/*javascript*
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|||||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
|||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v2
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.101
|
dotnet-version: 6.0.202
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|||||||
11
.github/workflows/query-list.yml
vendored
11
.github/workflows/query-list.yml
vendored
@@ -30,20 +30,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c
|
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||||
with:
|
uses: ./codeql/.github/actions/fetch-codeql
|
||||||
repo: "github/codeql-cli-binaries"
|
|
||||||
version: "latest"
|
|
||||||
file: "codeql-linux64.zip"
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Unzip CodeQL CLI
|
- name: Unzip CodeQL CLI
|
||||||
run: unzip -d codeql-cli codeql-linux64.zip
|
run: unzip -d codeql-cli codeql-linux64.zip
|
||||||
- name: Build code scanning query list
|
- name: Build code scanning query list
|
||||||
run: |
|
run: |
|
||||||
PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
||||||
- name: Upload code scanning query list
|
- name: Upload code scanning query list
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: code-scanning-query-list
|
name: code-scanning-query-list
|
||||||
path: code-scanning-query-list.csv
|
path: code-scanning-query-list.csv
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -37,5 +37,8 @@ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
|||||||
# links created by bazel
|
# links created by bazel
|
||||||
/bazel-*
|
/bazel-*
|
||||||
|
|
||||||
|
# local bazel options
|
||||||
|
/local.bazelrc
|
||||||
|
|
||||||
# CLion project files
|
# CLion project files
|
||||||
/.clwb
|
/.clwb
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
/javascript/ @github/codeql-javascript
|
/javascript/ @github/codeql-javascript
|
||||||
/python/ @github/codeql-python
|
/python/ @github/codeql-python
|
||||||
/ruby/ @github/codeql-ruby
|
/ruby/ @github/codeql-ruby
|
||||||
|
/swift/ @github/codeql-c
|
||||||
|
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||||
|
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||||
|
|
||||||
# ML-powered queries
|
# ML-powered queries
|
||||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* 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)`.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||||
|
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||||
|
|
||||||
## 0.1.0
|
## 0.1.0
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
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)`.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: deprecated
|
||||||
|
---
|
||||||
|
* The `AnalysedString` class in the `StringAnalysis` module has been replaced with `AnalyzedString`, to follow our style guide. The old name still exists as a deprecated alias.
|
||||||
10
cpp/ql/lib/change-notes/released/0.2.0.md
Normal file
10
cpp/ql/lib/change-notes/released/0.2.0.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* 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)`.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||||
|
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.1.0
|
lastReleaseVersion: 0.2.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.1.1-dev
|
version: 0.2.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
|||||||
* int z = min(5, 7);
|
* int z = min(5, 7);
|
||||||
* ```
|
* ```
|
||||||
* The full signature of the function called on the last line would be
|
* The full signature of the function called on the last line would be
|
||||||
* "min<int>(int, int) -> int", and the full signature of the uninstantiated
|
* `min<int>(int, int) -> int`, and the full signature of the uninstantiated
|
||||||
* template on the first line would be "min<T>(T, T) -> T".
|
* template on the first line would be `min<T>(T, T) -> T`.
|
||||||
*/
|
*/
|
||||||
string getFullSignature() {
|
string getFullSignature() {
|
||||||
exists(string name, string templateArgs, string args |
|
exists(string name, string templateArgs, string args |
|
||||||
|
|||||||
@@ -1312,7 +1312,7 @@ class FormatLiteral extends Literal {
|
|||||||
len =
|
len =
|
||||||
min(int v |
|
min(int v |
|
||||||
v = this.getPrecision(n) or
|
v = this.getPrecision(n) or
|
||||||
v = this.getUse().getFormatArgument(n).(AnalysedString).getMaxLength() - 1 // (don't count null terminator)
|
v = this.getUse().getFormatArgument(n).(AnalyzedString).getMaxLength() - 1 // (don't count null terminator)
|
||||||
) and
|
) and
|
||||||
reason = TValueFlowAnalysis()
|
reason = TValueFlowAnalysis()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,11 +27,14 @@ predicate canValueFlow(Expr fromExpr, Expr toExpr) {
|
|||||||
fromExpr = toExpr.(ConditionalExpr).getElse()
|
fromExpr = toExpr.(ConditionalExpr).getElse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for AnalyzedString */
|
||||||
|
deprecated class AnalysedString = AnalyzedString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An analysed null terminated string.
|
* An analyzed null terminated string.
|
||||||
*/
|
*/
|
||||||
class AnalysedString extends Expr {
|
class AnalyzedString extends Expr {
|
||||||
AnalysedString() {
|
AnalyzedString() {
|
||||||
this.getUnspecifiedType() instanceof ArrayType or
|
this.getUnspecifiedType() instanceof ArrayType or
|
||||||
this.getUnspecifiedType() instanceof PointerType
|
this.getUnspecifiedType() instanceof PointerType
|
||||||
}
|
}
|
||||||
@@ -41,15 +44,15 @@ class AnalysedString extends Expr {
|
|||||||
* can be calculated.
|
* can be calculated.
|
||||||
*/
|
*/
|
||||||
int getMaxLength() {
|
int getMaxLength() {
|
||||||
// take the longest AnalysedString it's value could 'flow' from; however if even one doesn't
|
// take the longest AnalyzedString its value could 'flow' from; however if even one doesn't
|
||||||
// return a value (this essentially means 'infinity') we can't return a value either.
|
// return a value (this essentially means 'infinity') we can't return a value either.
|
||||||
result =
|
result =
|
||||||
max(AnalysedString expr, int toMax |
|
max(AnalyzedString expr, int toMax |
|
||||||
canValueFlow*(expr, this) and toMax = expr.(StringLiteral).getOriginalLength()
|
canValueFlow*(expr, this) and toMax = expr.(StringLiteral).getOriginalLength()
|
||||||
|
|
|
|
||||||
toMax
|
toMax
|
||||||
) and // maximum length
|
) and // maximum length
|
||||||
forall(AnalysedString expr | canValueFlow(expr, this) | exists(expr.getMaxLength())) // all sources return a value (recursive)
|
forall(AnalyzedString expr | canValueFlow(expr, this) | exists(expr.getMaxLength())) // all sources return a value (recursive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -328,6 +328,9 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||||
|
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -198,6 +198,12 @@ predicate clearsContent(Node n, Content c) {
|
|||||||
none() // stub implementation
|
none() // stub implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||||
|
* at node `n`.
|
||||||
|
*/
|
||||||
|
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||||
|
|
||||||
/** Gets the type of `n` used for type pruning. */
|
/** Gets the type of `n` used for type pruning. */
|
||||||
Type getNodeType(Node n) {
|
Type getNodeType(Node n) {
|
||||||
suppressUnusedNode(n) and
|
suppressUnusedNode(n) and
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -328,6 +328,9 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||||
|
|
||||||
|
|||||||
@@ -279,6 +279,12 @@ predicate clearsContent(Node n, Content c) {
|
|||||||
none() // stub implementation
|
none() // stub implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||||
|
* at node `n`.
|
||||||
|
*/
|
||||||
|
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||||
|
|
||||||
/** Gets the type of `n` used for type pruning. */
|
/** Gets the type of `n` used for type pruning. */
|
||||||
IRType getNodeType(Node n) {
|
IRType getNodeType(Node n) {
|
||||||
suppressUnusedNode(n) and
|
suppressUnusedNode(n) and
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ class StrCopyBW extends BufferWriteCall {
|
|||||||
// when result exists, it is an exact flow analysis
|
// when result exists, it is an exact flow analysis
|
||||||
reason instanceof ValueFlowAnalysis and
|
reason instanceof ValueFlowAnalysis and
|
||||||
result =
|
result =
|
||||||
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
this.getArgument(this.getParamSrc()).(AnalyzedString).getMaxLength() * this.getCharSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getMaxData(BufferWriteEstimationReason reason) {
|
override int getMaxData(BufferWriteEstimationReason reason) {
|
||||||
@@ -201,7 +201,7 @@ class StrCatBW extends BufferWriteCall {
|
|||||||
// when result exists, it is an exact flow analysis
|
// when result exists, it is an exact flow analysis
|
||||||
reason instanceof ValueFlowAnalysis and
|
reason instanceof ValueFlowAnalysis and
|
||||||
result =
|
result =
|
||||||
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
this.getArgument(this.getParamSrc()).(AnalyzedString).getMaxLength() * this.getCharSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getMaxData(BufferWriteEstimationReason reason) {
|
override int getMaxData(BufferWriteEstimationReason reason) {
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.controlflow.Dominance
|
import semmle.code.cpp.controlflow.Dominance
|
||||||
// `GlobalValueNumbering` is only imported to prevent IR re-evaluation.
|
|
||||||
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
|
||||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||||
import semmle.code.cpp.controlflow.Guards
|
import semmle.code.cpp.controlflow.Guards
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
### New Queries
|
||||||
|
|
||||||
|
* An new query `cpp/external-entity-expansion` has been added. The query detects XML objects that are vulnerable to external entity expansion (XXE) attacks.
|
||||||
|
|
||||||
## 0.1.0
|
## 0.1.0
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
### Minor Analysis Improvements
|
||||||
|
|||||||
@@ -14,9 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
// We don't actually use the global value numbering library in this query, but without it we end up
|
|
||||||
// recomputing the IR.
|
|
||||||
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.ir.dataflow.MustFlow
|
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||||
import PathGraph
|
import PathGraph
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name Suspicious call to memset
|
* @name Suspicious call to memset
|
||||||
* @description Use of memset where the size argument is computed as the size of
|
* @description Use of memset where the size argument is computed as the size of
|
||||||
* some non-struct type. When initializing a buffer, you should specify
|
* some non-struct type. When initializing a buffer, you should specify
|
||||||
* its size as <number of elements> * <size of one element> to ensure
|
* its size as `<number of elements> * <size of one element>` to ensure
|
||||||
* portability.
|
* portability.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/suspicious-call-to-memset
|
* @id cpp/suspicious-call-to-memset
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
// We don't actually use the global value numbering library in this query, but without it we end up
|
|
||||||
// recomputing the IR.
|
|
||||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.ir.dataflow.MustFlow
|
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||||
import PathGraph
|
import PathGraph
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import cpp
|
|||||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A flow state representing a possible configuration of an XML object.
|
* A flow state representing a possible configuration of an XML object.
|
||||||
@@ -57,42 +58,58 @@ class XercesDOMParserClass extends Class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a valid flow state for `XercesDOMParser` flow.
|
* The `SAXParser` class.
|
||||||
|
*/
|
||||||
|
class SaxParserClass extends Class {
|
||||||
|
SaxParserClass() { this.hasName("SAXParser") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `SAX2XMLReader` class.
|
||||||
|
*/
|
||||||
|
class Sax2XmlReader extends Class {
|
||||||
|
Sax2XmlReader() { this.hasName("SAX2XMLReader") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a valid flow state for `AbstractDOMParser` or `SAXParser` flow.
|
||||||
*
|
*
|
||||||
* These flow states take the form `XercesDOM-A-B`, where:
|
* These flow states take the form `Xerces-A-B`, where:
|
||||||
* - A is 1 if `setDisableDefaultEntityResolution` is `true`, 0 otherwise.
|
* - A is 1 if `setDisableDefaultEntityResolution` is `true`, 0 otherwise.
|
||||||
* - B is 1 if `setCreateEntityReferenceNodes` is `true`, 0 otherwise.
|
* - B is 1 if `setCreateEntityReferenceNodes` is `true`, 0 otherwise.
|
||||||
*/
|
*/
|
||||||
predicate encodeXercesDOMFlowState(
|
predicate encodeXercesFlowState(
|
||||||
string flowstate, int disabledDefaultEntityResolution, int createEntityReferenceNodes
|
string flowstate, int disabledDefaultEntityResolution, int createEntityReferenceNodes
|
||||||
) {
|
) {
|
||||||
flowstate = "XercesDOM-0-0" and
|
flowstate = "Xerces-0-0" and
|
||||||
disabledDefaultEntityResolution = 0 and
|
disabledDefaultEntityResolution = 0 and
|
||||||
createEntityReferenceNodes = 0
|
createEntityReferenceNodes = 0
|
||||||
or
|
or
|
||||||
flowstate = "XercesDOM-0-1" and
|
flowstate = "Xerces-0-1" and
|
||||||
disabledDefaultEntityResolution = 0 and
|
disabledDefaultEntityResolution = 0 and
|
||||||
createEntityReferenceNodes = 1
|
createEntityReferenceNodes = 1
|
||||||
or
|
or
|
||||||
flowstate = "XercesDOM-1-0" and
|
flowstate = "Xerces-1-0" and
|
||||||
disabledDefaultEntityResolution = 1 and
|
disabledDefaultEntityResolution = 1 and
|
||||||
createEntityReferenceNodes = 0
|
createEntityReferenceNodes = 0
|
||||||
or
|
or
|
||||||
flowstate = "XercesDOM-1-1" and
|
flowstate = "Xerces-1-1" and
|
||||||
disabledDefaultEntityResolution = 1 and
|
disabledDefaultEntityResolution = 1 and
|
||||||
createEntityReferenceNodes = 1
|
createEntityReferenceNodes = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A flow state representing the configuration of a `XercesDOMParser` object.
|
* A flow state representing the configuration of an `AbstractDOMParser` or
|
||||||
|
* `SAXParser` object.
|
||||||
*/
|
*/
|
||||||
class XercesDOMParserFlowState extends XXEFlowState {
|
class XercesFlowState extends XXEFlowState {
|
||||||
XercesDOMParserFlowState() { encodeXercesDOMFlowState(this, _, _) }
|
XercesFlowState() { encodeXercesFlowState(this, _, _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A flow state transformer for a call to
|
* A flow state transformer for a call to
|
||||||
* `AbstractDOMParser.setDisableDefaultEntityResolution`. Transforms the flow
|
* `AbstractDOMParser.setDisableDefaultEntityResolution` or
|
||||||
|
* `SAXParser.setDisableDefaultEntityResolution`. Transforms the flow
|
||||||
* state through the qualifier according to the setting in the parameter.
|
* state through the qualifier according to the setting in the parameter.
|
||||||
*/
|
*/
|
||||||
class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer {
|
class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer {
|
||||||
@@ -101,7 +118,10 @@ class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer {
|
|||||||
DisableDefaultEntityResolutionTranformer() {
|
DisableDefaultEntityResolutionTranformer() {
|
||||||
exists(Call call, Function f |
|
exists(Call call, Function f |
|
||||||
call.getTarget() = f and
|
call.getTarget() = f and
|
||||||
f.getDeclaringType() instanceof AbstractDOMParserClass and
|
(
|
||||||
|
f.getDeclaringType() instanceof AbstractDOMParserClass or
|
||||||
|
f.getDeclaringType() instanceof SaxParserClass
|
||||||
|
) and
|
||||||
f.hasName("setDisableDefaultEntityResolution") and
|
f.hasName("setDisableDefaultEntityResolution") and
|
||||||
this = call.getQualifier() and
|
this = call.getQualifier() and
|
||||||
newValue = call.getArgument(0)
|
newValue = call.getArgument(0)
|
||||||
@@ -110,13 +130,13 @@ class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer {
|
|||||||
|
|
||||||
final override XXEFlowState transform(XXEFlowState flowstate) {
|
final override XXEFlowState transform(XXEFlowState flowstate) {
|
||||||
exists(int createEntityReferenceNodes |
|
exists(int createEntityReferenceNodes |
|
||||||
encodeXercesDOMFlowState(flowstate, _, createEntityReferenceNodes) and
|
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
||||||
(
|
(
|
||||||
newValue.getValue().toInt() = 1 and // true
|
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
||||||
encodeXercesDOMFlowState(result, 1, createEntityReferenceNodes)
|
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
||||||
or
|
or
|
||||||
not newValue.getValue().toInt() = 1 and // false or unknown
|
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
||||||
encodeXercesDOMFlowState(result, 0, createEntityReferenceNodes)
|
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -133,8 +153,7 @@ class CreateEntityReferenceNodesTranformer extends XXEFlowStateTranformer {
|
|||||||
CreateEntityReferenceNodesTranformer() {
|
CreateEntityReferenceNodesTranformer() {
|
||||||
exists(Call call, Function f |
|
exists(Call call, Function f |
|
||||||
call.getTarget() = f and
|
call.getTarget() = f and
|
||||||
f.getDeclaringType() instanceof AbstractDOMParserClass and
|
f.getClassAndName("setCreateEntityReferenceNodes") instanceof AbstractDOMParserClass and
|
||||||
f.hasName("setCreateEntityReferenceNodes") and
|
|
||||||
this = call.getQualifier() and
|
this = call.getQualifier() and
|
||||||
newValue = call.getArgument(0)
|
newValue = call.getArgument(0)
|
||||||
)
|
)
|
||||||
@@ -142,27 +161,76 @@ class CreateEntityReferenceNodesTranformer extends XXEFlowStateTranformer {
|
|||||||
|
|
||||||
final override XXEFlowState transform(XXEFlowState flowstate) {
|
final override XXEFlowState transform(XXEFlowState flowstate) {
|
||||||
exists(int disabledDefaultEntityResolution |
|
exists(int disabledDefaultEntityResolution |
|
||||||
encodeXercesDOMFlowState(flowstate, disabledDefaultEntityResolution, _) and
|
encodeXercesFlowState(flowstate, disabledDefaultEntityResolution, _) and
|
||||||
(
|
(
|
||||||
newValue.getValue().toInt() = 1 and // true
|
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
||||||
encodeXercesDOMFlowState(result, disabledDefaultEntityResolution, 1)
|
encodeXercesFlowState(result, disabledDefaultEntityResolution, 1)
|
||||||
or
|
or
|
||||||
not newValue.getValue().toInt() = 1 and // false or unknown
|
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
||||||
encodeXercesDOMFlowState(result, disabledDefaultEntityResolution, 0)
|
encodeXercesFlowState(result, disabledDefaultEntityResolution, 0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `AbstractDOMParser.parse` method.
|
* The `XMLUni.fgXercesDisableDefaultEntityResolution` constant.
|
||||||
*/
|
*/
|
||||||
class ParseFunction extends Function {
|
class FeatureDisableDefaultEntityResolution extends Variable {
|
||||||
ParseFunction() { this.getClassAndName("parse") instanceof AbstractDOMParserClass }
|
FeatureDisableDefaultEntityResolution() {
|
||||||
|
this.getName() = "fgXercesDisableDefaultEntityResolution" and
|
||||||
|
this.getDeclaringType().getName() = "XMLUni"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `createLSParser` function that returns a newly created `LSParser` object.
|
* A flow state transformer for a call to `SAX2XMLReader.setFeature`
|
||||||
|
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
|
||||||
|
* Transforms the flow state through the qualifier according to this setting.
|
||||||
|
*/
|
||||||
|
class SetFeatureTranformer extends XXEFlowStateTranformer {
|
||||||
|
Expr newValue;
|
||||||
|
|
||||||
|
SetFeatureTranformer() {
|
||||||
|
exists(Call call, Function f |
|
||||||
|
call.getTarget() = f and
|
||||||
|
f.getClassAndName("setFeature") instanceof Sax2XmlReader and
|
||||||
|
this = call.getQualifier() and
|
||||||
|
globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof
|
||||||
|
FeatureDisableDefaultEntityResolution and
|
||||||
|
newValue = call.getArgument(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override XXEFlowState transform(XXEFlowState flowstate) {
|
||||||
|
exists(int createEntityReferenceNodes |
|
||||||
|
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
||||||
|
(
|
||||||
|
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
||||||
|
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
||||||
|
or
|
||||||
|
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
||||||
|
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `AbstractDOMParser.parse`, `SAXParser.parse` or `SAX2XMLReader.parse`
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
class ParseFunction extends Function {
|
||||||
|
ParseFunction() {
|
||||||
|
this.getClassAndName("parse") instanceof AbstractDOMParserClass or
|
||||||
|
this.getClassAndName("parse") instanceof SaxParserClass or
|
||||||
|
this.getClassAndName("parse") instanceof Sax2XmlReader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `createLSParser` function that returns a newly created `DOMLSParser`
|
||||||
|
* object.
|
||||||
*/
|
*/
|
||||||
class CreateLSParser extends Function {
|
class CreateLSParser extends Function {
|
||||||
CreateLSParser() {
|
CreateLSParser() {
|
||||||
@@ -171,6 +239,53 @@ class CreateLSParser extends Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `createXMLReader` function that returns a newly created `SAX2XMLReader`
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
class CreateXmlReader extends Function {
|
||||||
|
CreateXmlReader() {
|
||||||
|
this.hasName("createXMLReader") and
|
||||||
|
this.getUnspecifiedType().(PointerType).getBaseType() instanceof Sax2XmlReader // returns a `SAX2XMLReader *`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to a `libxml2` function that parses XML.
|
||||||
|
*/
|
||||||
|
class Libxml2ParseCall extends FunctionCall {
|
||||||
|
int optionsArg;
|
||||||
|
|
||||||
|
Libxml2ParseCall() {
|
||||||
|
exists(string fname | this.getTarget().getName() = fname |
|
||||||
|
fname = "xmlCtxtUseOptions" and optionsArg = 1
|
||||||
|
or
|
||||||
|
fname = "xmlReadFile" and optionsArg = 2
|
||||||
|
or
|
||||||
|
fname = ["xmlCtxtReadFile", "xmlParseInNodeContext", "xmlReadDoc", "xmlReadFd"] and
|
||||||
|
optionsArg = 3
|
||||||
|
or
|
||||||
|
fname = ["xmlCtxtReadDoc", "xmlCtxtReadFd", "xmlReadMemory"] and optionsArg = 4
|
||||||
|
or
|
||||||
|
fname = ["xmlCtxtReadMemory", "xmlReadIO"] and optionsArg = 5
|
||||||
|
or
|
||||||
|
fname = "xmlCtxtReadIO" and optionsArg = 6
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the argument that specifies `xmlParserOption`s.
|
||||||
|
*/
|
||||||
|
Expr getOptions() { result = this.getArgument(optionsArg) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `xmlParserOption` for `libxml2` that is considered unsafe.
|
||||||
|
*/
|
||||||
|
class Libxml2BadOption extends EnumConstant {
|
||||||
|
Libxml2BadOption() { this.getName() = ["XML_PARSE_NOENT", "XML_PARSE_DTDLOAD"] }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A configuration for tracking XML objects and their states.
|
* A configuration for tracking XML objects and their states.
|
||||||
*/
|
*/
|
||||||
@@ -184,14 +299,47 @@ class XXEConfiguration extends DataFlow::Configuration {
|
|||||||
call.getStaticCallTarget() = any(XercesDOMParserClass c).getAConstructor() and
|
call.getStaticCallTarget() = any(XercesDOMParserClass c).getAConstructor() and
|
||||||
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
||||||
call.getThisArgument() and
|
call.getThisArgument() and
|
||||||
encodeXercesDOMFlowState(flowstate, 0, 1) // default configuration
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// source is the result of a call to `createLSParser`.
|
// source is the result of a call to `createLSParser`.
|
||||||
exists(Call call |
|
exists(Call call |
|
||||||
call.getTarget() instanceof CreateLSParser and
|
call.getTarget() instanceof CreateLSParser and
|
||||||
call = node.asExpr() and
|
call = node.asExpr() and
|
||||||
encodeXercesDOMFlowState(flowstate, 0, 1) // default configuration
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// source is the write on `this` of a call to the `SAXParser`
|
||||||
|
// constructor.
|
||||||
|
exists(CallInstruction call |
|
||||||
|
call.getStaticCallTarget() = any(SaxParserClass c).getAConstructor() and
|
||||||
|
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
||||||
|
call.getThisArgument() and
|
||||||
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// source is the result of a call to `createXMLReader`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget() instanceof CreateXmlReader and
|
||||||
|
call = node.asExpr() and
|
||||||
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// source is an `options` argument on a `libxml2` parse call that specifies
|
||||||
|
// at least one unsafe option.
|
||||||
|
//
|
||||||
|
// note: we don't need to track an XML object for `libxml2`, so we don't
|
||||||
|
// really need data flow. Nevertheless we jam it into this configuration,
|
||||||
|
// with matching sources and sinks. This allows results to be presented by
|
||||||
|
// the same query, in a consistent way as other results with flow paths.
|
||||||
|
exists(Libxml2ParseCall call, Expr options |
|
||||||
|
options = call.getOptions() and
|
||||||
|
node.asExpr() = options and
|
||||||
|
flowstate = "libxml2" and
|
||||||
|
exists(Libxml2BadOption opt |
|
||||||
|
globalValueNumber(options).getAnExpr().getValue().toInt().bitAnd(opt.getValue().toInt()) !=
|
||||||
|
0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,8 +349,15 @@ class XXEConfiguration extends DataFlow::Configuration {
|
|||||||
call.getTarget() instanceof ParseFunction and
|
call.getTarget() instanceof ParseFunction and
|
||||||
call.getQualifier() = node.asConvertedExpr()
|
call.getQualifier() = node.asConvertedExpr()
|
||||||
) and
|
) and
|
||||||
flowstate instanceof XercesDOMParserFlowState and
|
flowstate instanceof XercesFlowState and
|
||||||
not encodeXercesDOMFlowState(flowstate, 1, 1) // safe configuration
|
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
|
||||||
|
or
|
||||||
|
// sink is the `options` argument on a `libxml2` parse call.
|
||||||
|
exists(Libxml2ParseCall call, Expr options |
|
||||||
|
options = call.getOptions() and
|
||||||
|
node.asExpr() = options and
|
||||||
|
flowstate = "libxml2"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(
|
override predicate isAdditionalFlowStep(
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The "XML external entity expansion" (`cpp/external-entity-expansion`) query has been extended to support a broader selection of XML libraries and interfaces.
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
## 0.1.1
|
||||||
category: newQuery
|
|
||||||
---
|
### New Queries
|
||||||
|
|
||||||
* An new query `cpp/external-entity-expansion` has been added. The query detects XML objects that are vulnerable to external entity expansion (XXE) attacks.
|
* An new query `cpp/external-entity-expansion` has been added. The query detects XML objects that are vulnerable to external entity expansion (XXE) attacks.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.1.0
|
lastReleaseVersion: 0.1.1
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
...
|
||||||
|
try {
|
||||||
|
if (checkValue) throw exception();
|
||||||
|
bufMyData = new myData*[sizeInt];
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sizeInt; i++)
|
||||||
|
{
|
||||||
|
delete[] bufMyData[i]->buffer; // BAD
|
||||||
|
delete bufMyData[i];
|
||||||
|
}
|
||||||
|
...
|
||||||
|
try {
|
||||||
|
if (checkValue) throw exception();
|
||||||
|
bufMyData = new myData*[sizeInt];
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sizeInt; i++)
|
||||||
|
{
|
||||||
|
if(bufMyData[i])
|
||||||
|
{
|
||||||
|
delete[] bufMyData[i]->buffer; // GOOD
|
||||||
|
delete bufMyData[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
catch (const exception &) {
|
||||||
|
delete valData;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete valData; // BAD
|
||||||
|
...
|
||||||
|
catch (const exception &) {
|
||||||
|
delete valData;
|
||||||
|
valData = NULL;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete valData; // GOOD
|
||||||
|
...
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
<overview>
|
||||||
|
<p>When releasing memory in a catch block, be sure that the memory was allocated and has not already been released.</p>
|
||||||
|
|
||||||
|
</overview>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<p>The following example shows erroneous and fixed ways to use exception handling.</p>
|
||||||
|
<sample src="DangerousUseOfExceptionBlocks.cpp" />
|
||||||
|
|
||||||
|
</example>
|
||||||
|
<references>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
CERT C Coding Standard:
|
||||||
|
<a href="https://wiki.sei.cmu.edu/confluence/display/c/EXP34-C.+Do+not+dereference+null+pointers">EXP34-C. Do not dereference null pointers</a>.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
/**
|
||||||
|
* @name Dangerous use of exception blocks.
|
||||||
|
* @description When clearing the data in the catch block, you must be sure that the memory was allocated before the exception.
|
||||||
|
* @kind problem
|
||||||
|
* @id cpp/dangerous-use-of-exception-blocks
|
||||||
|
* @problem.severity warning
|
||||||
|
* @precision medium
|
||||||
|
* @tags correctness
|
||||||
|
* security
|
||||||
|
* external/cwe/cwe-476
|
||||||
|
* external/cwe/cwe-415
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
|
||||||
|
/** Holds if `vr` may be released in the `try` block associated with `cb`, or in a `catch` block prior to `cb`. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate doubleCallDelete(BlockStmt b, CatchAnyBlock cb, Variable vr) {
|
||||||
|
// Search for exceptions after freeing memory.
|
||||||
|
exists(Expr e1 |
|
||||||
|
// `e1` is a delete of `vr`
|
||||||
|
(
|
||||||
|
e1 = vr.getAnAccess().getEnclosingStmt().(ExprStmt).getExpr().(DeleteArrayExpr) or
|
||||||
|
e1 = vr.getAnAccess().getEnclosingStmt().(ExprStmt).getExpr().(DeleteExpr)
|
||||||
|
) and
|
||||||
|
e1.getEnclosingFunction() = cb.getEnclosingFunction() and
|
||||||
|
// there is no assignment `vr = 0` in the `try` block after `e1`
|
||||||
|
not exists(AssignExpr ae |
|
||||||
|
ae.getLValue().(VariableAccess).getTarget() = vr and
|
||||||
|
ae.getRValue().getValue() = "0" and
|
||||||
|
e1.getASuccessor+() = ae and
|
||||||
|
ae.getEnclosingStmt().getParentStmt*() = b
|
||||||
|
) and
|
||||||
|
// `e2` is a `throw` (or a function call that may throw) that occurs in the `try` or `catch` block after `e1`
|
||||||
|
exists(Expr e2, ThrowExpr th |
|
||||||
|
(
|
||||||
|
e2 = th or
|
||||||
|
e2 = th.getEnclosingFunction().getACallToThisFunction()
|
||||||
|
) and
|
||||||
|
e2.getEnclosingStmt().getParentStmt*() = b and
|
||||||
|
e1.getASuccessor+() = e2
|
||||||
|
) and
|
||||||
|
e1.getEnclosingStmt().getParentStmt*() = b and
|
||||||
|
(
|
||||||
|
// Search for a situation where there is a release in the block of `try`.
|
||||||
|
b = cb.getTryStmt().getStmt()
|
||||||
|
or
|
||||||
|
// Search for a situation when there is a higher catch block that also frees memory.
|
||||||
|
exists(b.(CatchBlock).getParameter())
|
||||||
|
) and
|
||||||
|
// Exclude the presence of a check in catch block.
|
||||||
|
not exists(IfStmt ifst | ifst.getEnclosingStmt().getParentStmt*() = cb.getAStmt())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if an exception can be thrown before the memory is allocated, and when the exception is handled, an attempt is made to access unallocated memory in the catch block. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate pointerDereference(CatchAnyBlock cb, Variable vr, Variable vro) {
|
||||||
|
// Search exceptions before allocating memory.
|
||||||
|
exists(Expr e0, Expr e1 |
|
||||||
|
(
|
||||||
|
// `e0` is a `new` expression (or equivalent function call) assigned to `vro`
|
||||||
|
exists(AssignExpr ase |
|
||||||
|
ase = vro.getAnAccess().getEnclosingStmt().(ExprStmt).getExpr() and
|
||||||
|
(
|
||||||
|
e0 = ase.getRValue().(NewOrNewArrayExpr) or
|
||||||
|
e0 = ase.getRValue().(NewOrNewArrayExpr).getEnclosingFunction().getACallToThisFunction()
|
||||||
|
) and
|
||||||
|
vro = ase.getLValue().(VariableAccess).getTarget()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// `e0` is a `new` expression (or equivalent function call) assigned to the array element `vro`
|
||||||
|
exists(AssignExpr ase |
|
||||||
|
ase = vro.getAnAccess().(Qualifier).getEnclosingStmt().(ExprStmt).getExpr() and
|
||||||
|
(
|
||||||
|
e0 = ase.getRValue().(NewOrNewArrayExpr) or
|
||||||
|
e0 = ase.getRValue().(NewOrNewArrayExpr).getEnclosingFunction().getACallToThisFunction()
|
||||||
|
) and
|
||||||
|
not ase.getLValue() instanceof VariableAccess and
|
||||||
|
vro = ase.getLValue().getAPredecessor().(VariableAccess).getTarget()
|
||||||
|
)
|
||||||
|
) and
|
||||||
|
// `e1` is a `new` expression (or equivalent function call) assigned to `vr`
|
||||||
|
exists(AssignExpr ase |
|
||||||
|
ase = vr.getAnAccess().getEnclosingStmt().(ExprStmt).getExpr() and
|
||||||
|
(
|
||||||
|
e1 = ase.getRValue().(NewOrNewArrayExpr) or
|
||||||
|
e1 = ase.getRValue().(NewOrNewArrayExpr).getEnclosingFunction().getACallToThisFunction()
|
||||||
|
) and
|
||||||
|
vr = ase.getLValue().(VariableAccess).getTarget()
|
||||||
|
) and
|
||||||
|
e0.getASuccessor*() = e1 and
|
||||||
|
e0.getEnclosingStmt().getParentStmt*() = cb.getTryStmt().getStmt() and
|
||||||
|
e1.getEnclosingStmt().getParentStmt*() = cb.getTryStmt().getStmt() and
|
||||||
|
// `e2` is a `throw` (or a function call that may throw) that occurs in the `try` block before `e0`
|
||||||
|
exists(Expr e2, ThrowExpr th |
|
||||||
|
(
|
||||||
|
e2 = th or
|
||||||
|
e2 = th.getEnclosingFunction().getACallToThisFunction()
|
||||||
|
) and
|
||||||
|
e2.getEnclosingStmt().getParentStmt*() = cb.getTryStmt().getStmt() and
|
||||||
|
e2.getASuccessor+() = e0
|
||||||
|
)
|
||||||
|
) and
|
||||||
|
// We exclude checking the value of a variable or its parent in the catch block.
|
||||||
|
not exists(IfStmt ifst |
|
||||||
|
ifst.getEnclosingStmt().getParentStmt*() = cb.getAStmt() and
|
||||||
|
(
|
||||||
|
ifst.getCondition().getAChild*().(VariableAccess).getTarget() = vr or
|
||||||
|
ifst.getCondition().getAChild*().(VariableAccess).getTarget() = vro
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `vro` may be released in the `catch`. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate newThrowDelete(CatchAnyBlock cb, Variable vro) {
|
||||||
|
exists(Expr e0, AssignExpr ase, NewOrNewArrayExpr nae |
|
||||||
|
ase = vro.getAnAccess().getEnclosingStmt().(ExprStmt).getExpr() and
|
||||||
|
nae = ase.getRValue() and
|
||||||
|
not nae.getAChild*().toString() = "nothrow" and
|
||||||
|
(
|
||||||
|
e0 = nae or
|
||||||
|
e0 = nae.getEnclosingFunction().getACallToThisFunction()
|
||||||
|
) and
|
||||||
|
vro = ase.getLValue().(VariableAccess).getTarget() and
|
||||||
|
e0.getEnclosingStmt().getParentStmt*() = cb.getTryStmt().getStmt() and
|
||||||
|
not exists(AssignExpr ase1 |
|
||||||
|
vro = ase1.getLValue().(VariableAccess).getTarget() and
|
||||||
|
ase1.getRValue().getValue() = "0" and
|
||||||
|
ase1.getASuccessor*() = e0
|
||||||
|
)
|
||||||
|
) and
|
||||||
|
not exists(Initializer it |
|
||||||
|
vro.getInitializer() = it and
|
||||||
|
it.getExpr().getValue() = "0"
|
||||||
|
) and
|
||||||
|
not exists(ConstructorFieldInit ci | vro = ci.getTarget())
|
||||||
|
}
|
||||||
|
|
||||||
|
from CatchAnyBlock cb, string msg
|
||||||
|
where
|
||||||
|
exists(Variable vr, Variable vro, Expr exp |
|
||||||
|
exp.getEnclosingStmt().getParentStmt*() = cb and
|
||||||
|
exists(VariableAccess va |
|
||||||
|
(
|
||||||
|
(
|
||||||
|
va = exp.(DeleteArrayExpr).getExpr().getAPredecessor+().(Qualifier) or
|
||||||
|
va = exp.(DeleteArrayExpr).getExpr().getAPredecessor+()
|
||||||
|
) and
|
||||||
|
vr = exp.(DeleteArrayExpr).getExpr().(VariableAccess).getTarget()
|
||||||
|
or
|
||||||
|
(
|
||||||
|
va = exp.(DeleteExpr).getExpr().getAPredecessor+().(Qualifier) or
|
||||||
|
va = exp.(DeleteExpr).getExpr().getAPredecessor+()
|
||||||
|
) and
|
||||||
|
vr = exp.(DeleteExpr).getExpr().(VariableAccess).getTarget()
|
||||||
|
) and
|
||||||
|
va.getEnclosingStmt() = exp.getEnclosingStmt() and
|
||||||
|
vro = va.getTarget() and
|
||||||
|
vr != vro
|
||||||
|
) and
|
||||||
|
pointerDereference(cb, vr, vro) and
|
||||||
|
msg =
|
||||||
|
"it is possible to dereference a pointer when accessing a " + vr.getName() +
|
||||||
|
", since it is possible to throw an exception before the memory for the " + vro.getName() +
|
||||||
|
" is allocated"
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(Expr exp, Variable vr |
|
||||||
|
(
|
||||||
|
exp.(DeleteExpr).getEnclosingStmt().getParentStmt*() = cb and
|
||||||
|
vr = exp.(DeleteExpr).getExpr().(VariableAccess).getTarget()
|
||||||
|
or
|
||||||
|
exp.(DeleteArrayExpr).getEnclosingStmt().getParentStmt*() = cb and
|
||||||
|
vr = exp.(DeleteArrayExpr).getExpr().(VariableAccess).getTarget()
|
||||||
|
) and
|
||||||
|
doubleCallDelete(_, cb, vr) and
|
||||||
|
msg =
|
||||||
|
"This allocation may have been released in the try block or a previous catch block." +
|
||||||
|
vr.getName()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(Variable vro, Expr exp |
|
||||||
|
exp.getEnclosingStmt().getParentStmt*() = cb and
|
||||||
|
exists(VariableAccess va |
|
||||||
|
(
|
||||||
|
va = exp.(DeleteArrayExpr).getExpr() or
|
||||||
|
va = exp.(DeleteExpr).getExpr()
|
||||||
|
) and
|
||||||
|
va.getEnclosingStmt() = exp.getEnclosingStmt() and
|
||||||
|
vro = va.getTarget()
|
||||||
|
) and
|
||||||
|
newThrowDelete(cb, vro) and
|
||||||
|
msg =
|
||||||
|
"If the allocation in the try block fails, then an unallocated pointer " + vro.getName() +
|
||||||
|
" will be freed in the catch block."
|
||||||
|
)
|
||||||
|
select cb, msg
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.1.1-dev
|
version: 0.1.2-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
| test.cpp:14:16:14:16 | p | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:14:16:14:16 | p | p |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
experimental/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser.ql
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
|
||||||
|
void SYSC_SOMESYSTEMCALL(void *param);
|
||||||
|
|
||||||
|
bool user_access_begin_impl(const void *where, size_t sz);
|
||||||
|
void user_access_end_impl();
|
||||||
|
#define user_access_begin(where, sz) user_access_begin_impl(where, sz)
|
||||||
|
#define user_access_end() user_access_end_impl()
|
||||||
|
|
||||||
|
void unsafe_put_user_impl(int what, const void *where, size_t sz);
|
||||||
|
#define unsafe_put_user(what, where) unsafe_put_user_impl( (what), (where), sizeof(*(where)) )
|
||||||
|
|
||||||
|
void test1(int p)
|
||||||
|
{
|
||||||
|
SYSC_SOMESYSTEMCALL(&p);
|
||||||
|
|
||||||
|
unsafe_put_user(123, &p); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test2(int p)
|
||||||
|
{
|
||||||
|
SYSC_SOMESYSTEMCALL(&p);
|
||||||
|
|
||||||
|
if (user_access_begin(&p, sizeof(p)))
|
||||||
|
{
|
||||||
|
unsafe_put_user(123, &p); // GOOD
|
||||||
|
|
||||||
|
user_access_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test3()
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
SYSC_SOMESYSTEMCALL(&v);
|
||||||
|
|
||||||
|
unsafe_put_user(123, &v); // BAD [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4()
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
SYSC_SOMESYSTEMCALL(&v);
|
||||||
|
|
||||||
|
if (user_access_begin(&v, sizeof(v)))
|
||||||
|
{
|
||||||
|
unsafe_put_user(123, &v); // GOOD
|
||||||
|
|
||||||
|
user_access_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
};
|
||||||
|
|
||||||
|
void test5()
|
||||||
|
{
|
||||||
|
data myData;
|
||||||
|
|
||||||
|
SYSC_SOMESYSTEMCALL(&myData);
|
||||||
|
|
||||||
|
unsafe_put_user(123, &(myData.x)); // BAD [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test6()
|
||||||
|
{
|
||||||
|
data myData;
|
||||||
|
|
||||||
|
SYSC_SOMESYSTEMCALL(&myData);
|
||||||
|
|
||||||
|
if (user_access_begin(&myData, sizeof(myData)))
|
||||||
|
{
|
||||||
|
unsafe_put_user(123, &(myData.x)); // GOOD
|
||||||
|
|
||||||
|
user_access_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
| test.cpp:63:3:71:3 | { ... } | If the allocation in the try block fails, then an unallocated pointer bufMyData will be freed in the catch block. |
|
||||||
|
| test.cpp:63:3:71:3 | { ... } | If the allocation in the try block fails, then an unallocated pointer buffer will be freed in the catch block. |
|
||||||
|
| test.cpp:63:3:71:3 | { ... } | it is possible to dereference a pointer when accessing a buffer, since it is possible to throw an exception before the memory for the bufMyData is allocated |
|
||||||
|
| test.cpp:91:3:100:3 | { ... } | If the allocation in the try block fails, then an unallocated pointer buffer will be freed in the catch block. |
|
||||||
|
| test.cpp:120:3:128:3 | { ... } | If the allocation in the try block fails, then an unallocated pointer buffer will be freed in the catch block. |
|
||||||
|
| test.cpp:143:3:151:3 | { ... } | If the allocation in the try block fails, then an unallocated pointer buffer will be freed in the catch block. |
|
||||||
|
| test.cpp:181:3:183:3 | { ... } | This allocation may have been released in the try block or a previous catch block.valData |
|
||||||
|
| test.cpp:219:3:221:3 | { ... } | This allocation may have been released in the try block or a previous catch block.valData |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
experimental/Security/CWE/CWE-476/DangerousUseOfExceptionBlocks.ql
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
#define NULL ((void*)0)
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
namespace std {
|
||||||
|
enum class align_val_t : size_t {};
|
||||||
|
}
|
||||||
|
|
||||||
|
class exception {};
|
||||||
|
|
||||||
|
void cleanFunction();
|
||||||
|
|
||||||
|
void* operator new(size_t, float);
|
||||||
|
void* operator new[](size_t, float);
|
||||||
|
void* operator new(size_t, std::align_val_t, float);
|
||||||
|
void* operator new[](size_t, std::align_val_t, float);
|
||||||
|
void operator delete(void*, float);
|
||||||
|
void operator delete[](void*, float);
|
||||||
|
void operator delete(void*, std::align_val_t, float);
|
||||||
|
void operator delete[](void*, std::align_val_t, float);
|
||||||
|
|
||||||
|
struct myData
|
||||||
|
{
|
||||||
|
int sizeInt;
|
||||||
|
char* buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct myGlobalData
|
||||||
|
{
|
||||||
|
int sizeInt;
|
||||||
|
myData** bufMyData;
|
||||||
|
};
|
||||||
|
|
||||||
|
void allocData(myData ** bufMyData) {
|
||||||
|
for (size_t i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
bufMyData[i] = new myData;
|
||||||
|
bufMyData[i]->sizeInt = 10;
|
||||||
|
bufMyData[i]->buffer = new char[10];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void throwFunction(int a) {
|
||||||
|
if (a == 5) throw "my exception!";
|
||||||
|
}
|
||||||
|
void throwFunction2(int a) {
|
||||||
|
if (a == 5) throw exception();
|
||||||
|
}
|
||||||
|
void funcWork1b() {
|
||||||
|
int a;
|
||||||
|
myData **bufMyData;
|
||||||
|
|
||||||
|
try {
|
||||||
|
cleanFunction();
|
||||||
|
throwFunction(a);
|
||||||
|
|
||||||
|
bufMyData = new myData*[10];
|
||||||
|
cleanFunction();
|
||||||
|
allocData(bufMyData);
|
||||||
|
cleanFunction();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
delete[] bufMyData[i]->buffer; // BAD
|
||||||
|
delete bufMyData[i];
|
||||||
|
}
|
||||||
|
delete [] bufMyData;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void funcWork1() {
|
||||||
|
int a;
|
||||||
|
int i;
|
||||||
|
myData **bufMyData;
|
||||||
|
|
||||||
|
bufMyData = new myData*[10];
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
bufMyData[i] = 0;
|
||||||
|
try {
|
||||||
|
cleanFunction();
|
||||||
|
throwFunction(a);
|
||||||
|
cleanFunction();
|
||||||
|
allocData(bufMyData);
|
||||||
|
cleanFunction();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (bufMyData[i])
|
||||||
|
delete[] bufMyData[i]->buffer; // BAD
|
||||||
|
delete bufMyData[i];
|
||||||
|
}
|
||||||
|
delete [] bufMyData;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void funcWork2() {
|
||||||
|
int a;
|
||||||
|
myData **bufMyData;
|
||||||
|
|
||||||
|
bufMyData = new myData*[10];
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
cleanFunction();
|
||||||
|
allocData(bufMyData);
|
||||||
|
cleanFunction();
|
||||||
|
throwFunction(a);
|
||||||
|
|
||||||
|
}
|
||||||
|
while(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
delete[] bufMyData[i]->buffer; // BAD
|
||||||
|
delete bufMyData[i];
|
||||||
|
}
|
||||||
|
delete [] bufMyData;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void funcWork3() {
|
||||||
|
int a;
|
||||||
|
myData **bufMyData;
|
||||||
|
|
||||||
|
bufMyData = new myData*[10];
|
||||||
|
try {
|
||||||
|
cleanFunction();
|
||||||
|
allocData(bufMyData);
|
||||||
|
cleanFunction();
|
||||||
|
throwFunction(a);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
delete[] bufMyData[i]->buffer; // BAD
|
||||||
|
delete bufMyData[i];
|
||||||
|
}
|
||||||
|
delete [] bufMyData;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void funcWork4() {
|
||||||
|
int a;
|
||||||
|
myGlobalData *valData = 0;
|
||||||
|
try {
|
||||||
|
valData = new myGlobalData;
|
||||||
|
cleanFunction();
|
||||||
|
delete valData;
|
||||||
|
valData = 0;
|
||||||
|
throwFunction(a);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete valData; // GOOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void funcWork4b() {
|
||||||
|
int a;
|
||||||
|
myGlobalData *valData = 0;
|
||||||
|
try {
|
||||||
|
valData = new myGlobalData;
|
||||||
|
cleanFunction();
|
||||||
|
delete valData;
|
||||||
|
throwFunction(a);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete valData; // BAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void funcWork5() {
|
||||||
|
int a;
|
||||||
|
myGlobalData *valData = 0;
|
||||||
|
try {
|
||||||
|
valData = new myGlobalData;
|
||||||
|
cleanFunction();
|
||||||
|
delete valData;
|
||||||
|
valData = 0;
|
||||||
|
throwFunction2(a);
|
||||||
|
}
|
||||||
|
catch (const exception &) {
|
||||||
|
delete valData;
|
||||||
|
valData = 0;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete valData; // GOOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void funcWork5b() {
|
||||||
|
int a;
|
||||||
|
myGlobalData *valData = 0;
|
||||||
|
try {
|
||||||
|
valData = new myGlobalData;
|
||||||
|
cleanFunction();
|
||||||
|
throwFunction2(a);
|
||||||
|
}
|
||||||
|
catch (const exception &) {
|
||||||
|
delete valData;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete valData; // BAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void funcWork6() {
|
||||||
|
int a;
|
||||||
|
int flagB = 0;
|
||||||
|
myGlobalData *valData = 0;
|
||||||
|
try {
|
||||||
|
valData = new myGlobalData;
|
||||||
|
cleanFunction();
|
||||||
|
throwFunction2(a);
|
||||||
|
}
|
||||||
|
catch (const exception &) {
|
||||||
|
delete valData;
|
||||||
|
flagB = 1;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
if(flagB == 0)
|
||||||
|
delete valData; // GOOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runnerFunc()
|
||||||
|
{
|
||||||
|
funcWork1();
|
||||||
|
funcWork1b();
|
||||||
|
funcWork2();
|
||||||
|
funcWork3();
|
||||||
|
funcWork4();
|
||||||
|
funcWork4b();
|
||||||
|
funcWork5();
|
||||||
|
funcWork5b();
|
||||||
|
funcWork6();
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
from AnalysedString s, string str
|
from AnalyzedString s, string str
|
||||||
where
|
where
|
||||||
if s.(StringLiteral).getUnspecifiedType().(DerivedType).getBaseType() instanceof Wchar_t
|
if s.(StringLiteral).getUnspecifiedType().(DerivedType).getBaseType() instanceof Wchar_t
|
||||||
then str = "[?]"
|
then str = "[?]"
|
||||||
|
|||||||
@@ -1,80 +1,106 @@
|
|||||||
edges
|
edges
|
||||||
| tests.cpp:33:23:33:43 | XercesDOMParser output argument | tests.cpp:35:2:35:2 | p |
|
| tests2.cpp:20:17:20:31 | SAXParser output argument | tests2.cpp:22:2:22:2 | p |
|
||||||
| tests.cpp:46:23:46:43 | XercesDOMParser output argument | tests.cpp:49:2:49:2 | p |
|
| tests2.cpp:33:17:33:31 | SAXParser output argument | tests2.cpp:37:2:37:2 | p |
|
||||||
| tests.cpp:53:19:53:19 | VariableAddress [post update] | tests.cpp:55:2:55:2 | p |
|
| tests3.cpp:23:21:23:53 | call to createXMLReader | tests3.cpp:25:2:25:2 | p |
|
||||||
| tests.cpp:53:23:53:43 | XercesDOMParser output argument | tests.cpp:53:19:53:19 | VariableAddress [post update] |
|
| tests3.cpp:60:21:60:53 | call to createXMLReader | tests3.cpp:63:2:63:2 | p |
|
||||||
|
| tests3.cpp:67:21:67:53 | call to createXMLReader | tests3.cpp:70:2:70:2 | p |
|
||||||
|
| tests.cpp:15:23:15:43 | XercesDOMParser output argument | tests.cpp:17:2:17:2 | p |
|
||||||
|
| tests.cpp:28:23:28:43 | XercesDOMParser output argument | tests.cpp:31:2:31:2 | p |
|
||||||
|
| tests.cpp:35:19:35:19 | VariableAddress [post update] | tests.cpp:37:2:37:2 | p |
|
||||||
|
| tests.cpp:35:23:35:43 | XercesDOMParser output argument | tests.cpp:35:19:35:19 | VariableAddress [post update] |
|
||||||
|
| tests.cpp:37:2:37:2 | p | tests.cpp:38:2:38:2 | p |
|
||||||
|
| tests.cpp:38:2:38:2 | p | tests.cpp:39:2:39:2 | p |
|
||||||
|
| tests.cpp:51:19:51:19 | VariableAddress [post update] | tests.cpp:53:2:53:2 | p |
|
||||||
|
| tests.cpp:51:23:51:43 | XercesDOMParser output argument | tests.cpp:51:19:51:19 | VariableAddress [post update] |
|
||||||
|
| tests.cpp:53:2:53:2 | p | tests.cpp:54:2:54:2 | p |
|
||||||
|
| tests.cpp:54:2:54:2 | p | tests.cpp:55:2:55:2 | p |
|
||||||
|
| tests.cpp:55:2:55:2 | p | tests.cpp:56:2:56:2 | p |
|
||||||
| tests.cpp:55:2:55:2 | p | tests.cpp:56:2:56:2 | p |
|
| tests.cpp:55:2:55:2 | p | tests.cpp:56:2:56:2 | p |
|
||||||
| tests.cpp:56:2:56:2 | p | tests.cpp:57:2:57:2 | p |
|
| tests.cpp:56:2:56:2 | p | tests.cpp:57:2:57:2 | p |
|
||||||
| tests.cpp:69:19:69:19 | VariableAddress [post update] | tests.cpp:71:2:71:2 | p |
|
| tests.cpp:57:2:57:2 | p | tests.cpp:58:2:58:2 | p |
|
||||||
| tests.cpp:69:23:69:43 | XercesDOMParser output argument | tests.cpp:69:19:69:19 | VariableAddress [post update] |
|
| tests.cpp:58:2:58:2 | p | tests.cpp:59:2:59:2 | p |
|
||||||
| tests.cpp:71:2:71:2 | p | tests.cpp:72:2:72:2 | p |
|
| tests.cpp:59:2:59:2 | p | tests.cpp:60:2:60:2 | p |
|
||||||
| tests.cpp:72:2:72:2 | p | tests.cpp:73:2:73:2 | p |
|
| tests.cpp:66:23:66:43 | XercesDOMParser output argument | tests.cpp:69:2:69:2 | p |
|
||||||
| tests.cpp:73:2:73:2 | p | tests.cpp:74:2:74:2 | p |
|
| tests.cpp:73:23:73:43 | XercesDOMParser output argument | tests.cpp:80:2:80:2 | p |
|
||||||
| tests.cpp:73:2:73:2 | p | tests.cpp:74:2:74:2 | p |
|
| tests.cpp:85:24:85:44 | XercesDOMParser output argument | tests.cpp:88:3:88:3 | q |
|
||||||
| tests.cpp:74:2:74:2 | p | tests.cpp:75:2:75:2 | p |
|
| tests.cpp:100:24:100:44 | XercesDOMParser output argument | tests.cpp:104:3:104:3 | q |
|
||||||
| tests.cpp:75:2:75:2 | p | tests.cpp:76:2:76:2 | p |
|
| tests.cpp:112:39:112:39 | p | tests.cpp:113:2:113:2 | p |
|
||||||
| tests.cpp:76:2:76:2 | p | tests.cpp:77:2:77:2 | p |
|
| tests.cpp:116:39:116:39 | p | tests.cpp:117:2:117:2 | p |
|
||||||
| tests.cpp:77:2:77:2 | p | tests.cpp:78:2:78:2 | p |
|
| tests.cpp:122:23:122:43 | XercesDOMParser output argument | tests.cpp:126:18:126:18 | q |
|
||||||
| tests.cpp:84:23:84:43 | XercesDOMParser output argument | tests.cpp:87:2:87:2 | p |
|
| tests.cpp:122:23:122:43 | XercesDOMParser output argument | tests.cpp:128:18:128:18 | q |
|
||||||
| tests.cpp:91:23:91:43 | XercesDOMParser output argument | tests.cpp:98:2:98:2 | p |
|
| tests.cpp:126:18:126:18 | q | tests.cpp:112:39:112:39 | p |
|
||||||
| tests.cpp:103:24:103:44 | XercesDOMParser output argument | tests.cpp:106:3:106:3 | q |
|
| tests.cpp:128:18:128:18 | q | tests.cpp:116:39:116:39 | p |
|
||||||
| tests.cpp:118:24:118:44 | XercesDOMParser output argument | tests.cpp:122:3:122:3 | q |
|
|
||||||
| tests.cpp:130:39:130:39 | p | tests.cpp:131:2:131:2 | p |
|
|
||||||
| tests.cpp:134:39:134:39 | p | tests.cpp:135:2:135:2 | p |
|
|
||||||
| tests.cpp:140:23:140:43 | XercesDOMParser output argument | tests.cpp:144:18:144:18 | q |
|
|
||||||
| tests.cpp:140:23:140:43 | XercesDOMParser output argument | tests.cpp:146:18:146:18 | q |
|
|
||||||
| tests.cpp:144:18:144:18 | q | tests.cpp:130:39:130:39 | p |
|
|
||||||
| tests.cpp:146:18:146:18 | q | tests.cpp:134:39:134:39 | p |
|
|
||||||
| tests.cpp:150:19:150:32 | call to createLSParser | tests.cpp:152:2:152:2 | p |
|
|
||||||
nodes
|
nodes
|
||||||
| tests.cpp:33:23:33:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests2.cpp:20:17:20:31 | SAXParser output argument | semmle.label | SAXParser output argument |
|
||||||
| tests.cpp:35:2:35:2 | p | semmle.label | p |
|
| tests2.cpp:22:2:22:2 | p | semmle.label | p |
|
||||||
| tests.cpp:46:23:46:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests2.cpp:33:17:33:31 | SAXParser output argument | semmle.label | SAXParser output argument |
|
||||||
| tests.cpp:49:2:49:2 | p | semmle.label | p |
|
| tests2.cpp:37:2:37:2 | p | semmle.label | p |
|
||||||
| tests.cpp:53:19:53:19 | VariableAddress [post update] | semmle.label | VariableAddress [post update] |
|
| tests3.cpp:23:21:23:53 | call to createXMLReader | semmle.label | call to createXMLReader |
|
||||||
| tests.cpp:53:23:53:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests3.cpp:25:2:25:2 | p | semmle.label | p |
|
||||||
|
| tests3.cpp:60:21:60:53 | call to createXMLReader | semmle.label | call to createXMLReader |
|
||||||
|
| tests3.cpp:63:2:63:2 | p | semmle.label | p |
|
||||||
|
| tests3.cpp:67:21:67:53 | call to createXMLReader | semmle.label | call to createXMLReader |
|
||||||
|
| tests3.cpp:70:2:70:2 | p | semmle.label | p |
|
||||||
|
| tests4.cpp:26:34:26:48 | (int)... | semmle.label | (int)... |
|
||||||
|
| tests4.cpp:36:34:36:50 | (int)... | semmle.label | (int)... |
|
||||||
|
| tests4.cpp:46:34:46:68 | ... \| ... | semmle.label | ... \| ... |
|
||||||
|
| tests4.cpp:77:34:77:38 | flags | semmle.label | flags |
|
||||||
|
| tests4.cpp:130:39:130:55 | (int)... | semmle.label | (int)... |
|
||||||
|
| tests.cpp:15:23:15:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
|
| tests.cpp:17:2:17:2 | p | semmle.label | p |
|
||||||
|
| tests.cpp:28:23:28:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
|
| tests.cpp:31:2:31:2 | p | semmle.label | p |
|
||||||
|
| tests.cpp:35:19:35:19 | VariableAddress [post update] | semmle.label | VariableAddress [post update] |
|
||||||
|
| tests.cpp:35:23:35:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
|
| tests.cpp:37:2:37:2 | p | semmle.label | p |
|
||||||
|
| tests.cpp:38:2:38:2 | p | semmle.label | p |
|
||||||
|
| tests.cpp:39:2:39:2 | p | semmle.label | p |
|
||||||
|
| tests.cpp:51:19:51:19 | VariableAddress [post update] | semmle.label | VariableAddress [post update] |
|
||||||
|
| tests.cpp:51:23:51:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
|
| tests.cpp:53:2:53:2 | p | semmle.label | p |
|
||||||
|
| tests.cpp:54:2:54:2 | p | semmle.label | p |
|
||||||
| tests.cpp:55:2:55:2 | p | semmle.label | p |
|
| tests.cpp:55:2:55:2 | p | semmle.label | p |
|
||||||
| tests.cpp:56:2:56:2 | p | semmle.label | p |
|
| tests.cpp:56:2:56:2 | p | semmle.label | p |
|
||||||
|
| tests.cpp:56:2:56:2 | p | semmle.label | p |
|
||||||
| tests.cpp:57:2:57:2 | p | semmle.label | p |
|
| tests.cpp:57:2:57:2 | p | semmle.label | p |
|
||||||
| tests.cpp:69:19:69:19 | VariableAddress [post update] | semmle.label | VariableAddress [post update] |
|
| tests.cpp:58:2:58:2 | p | semmle.label | p |
|
||||||
| tests.cpp:69:23:69:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests.cpp:59:2:59:2 | p | semmle.label | p |
|
||||||
| tests.cpp:71:2:71:2 | p | semmle.label | p |
|
| tests.cpp:60:2:60:2 | p | semmle.label | p |
|
||||||
| tests.cpp:72:2:72:2 | p | semmle.label | p |
|
| tests.cpp:66:23:66:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
| tests.cpp:73:2:73:2 | p | semmle.label | p |
|
| tests.cpp:69:2:69:2 | p | semmle.label | p |
|
||||||
| tests.cpp:74:2:74:2 | p | semmle.label | p |
|
| tests.cpp:73:23:73:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
| tests.cpp:74:2:74:2 | p | semmle.label | p |
|
| tests.cpp:80:2:80:2 | p | semmle.label | p |
|
||||||
| tests.cpp:75:2:75:2 | p | semmle.label | p |
|
| tests.cpp:85:24:85:44 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
| tests.cpp:76:2:76:2 | p | semmle.label | p |
|
| tests.cpp:88:3:88:3 | q | semmle.label | q |
|
||||||
| tests.cpp:77:2:77:2 | p | semmle.label | p |
|
| tests.cpp:100:24:100:44 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
| tests.cpp:78:2:78:2 | p | semmle.label | p |
|
| tests.cpp:104:3:104:3 | q | semmle.label | q |
|
||||||
| tests.cpp:84:23:84:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests.cpp:112:39:112:39 | p | semmle.label | p |
|
||||||
| tests.cpp:87:2:87:2 | p | semmle.label | p |
|
| tests.cpp:113:2:113:2 | p | semmle.label | p |
|
||||||
| tests.cpp:91:23:91:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests.cpp:116:39:116:39 | p | semmle.label | p |
|
||||||
| tests.cpp:98:2:98:2 | p | semmle.label | p |
|
| tests.cpp:117:2:117:2 | p | semmle.label | p |
|
||||||
| tests.cpp:103:24:103:44 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests.cpp:122:23:122:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||||
| tests.cpp:106:3:106:3 | q | semmle.label | q |
|
| tests.cpp:126:18:126:18 | q | semmle.label | q |
|
||||||
| tests.cpp:118:24:118:44 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
| tests.cpp:128:18:128:18 | q | semmle.label | q |
|
||||||
| tests.cpp:122:3:122:3 | q | semmle.label | q |
|
|
||||||
| tests.cpp:130:39:130:39 | p | semmle.label | p |
|
|
||||||
| tests.cpp:131:2:131:2 | p | semmle.label | p |
|
|
||||||
| tests.cpp:134:39:134:39 | p | semmle.label | p |
|
|
||||||
| tests.cpp:135:2:135:2 | p | semmle.label | p |
|
|
||||||
| tests.cpp:140:23:140:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
|
||||||
| tests.cpp:144:18:144:18 | q | semmle.label | q |
|
|
||||||
| tests.cpp:146:18:146:18 | q | semmle.label | q |
|
|
||||||
| tests.cpp:150:19:150:32 | call to createLSParser | semmle.label | call to createLSParser |
|
|
||||||
| tests.cpp:152:2:152:2 | p | semmle.label | p |
|
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
#select
|
||||||
| tests.cpp:35:2:35:2 | p | tests.cpp:33:23:33:43 | XercesDOMParser output argument | tests.cpp:35:2:35:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:33:23:33:43 | XercesDOMParser output argument | XML parser |
|
| tests2.cpp:22:2:22:2 | p | tests2.cpp:20:17:20:31 | SAXParser output argument | tests2.cpp:22:2:22:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests2.cpp:20:17:20:31 | SAXParser output argument | XML parser |
|
||||||
| tests.cpp:49:2:49:2 | p | tests.cpp:46:23:46:43 | XercesDOMParser output argument | tests.cpp:49:2:49:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:46:23:46:43 | XercesDOMParser output argument | XML parser |
|
| tests2.cpp:37:2:37:2 | p | tests2.cpp:33:17:33:31 | SAXParser output argument | tests2.cpp:37:2:37:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests2.cpp:33:17:33:31 | SAXParser output argument | XML parser |
|
||||||
| tests.cpp:57:2:57:2 | p | tests.cpp:53:23:53:43 | XercesDOMParser output argument | tests.cpp:57:2:57:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:53:23:53:43 | XercesDOMParser output argument | XML parser |
|
| tests3.cpp:25:2:25:2 | p | tests3.cpp:23:21:23:53 | call to createXMLReader | tests3.cpp:25:2:25:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests3.cpp:23:21:23:53 | call to createXMLReader | XML parser |
|
||||||
| tests.cpp:74:2:74:2 | p | tests.cpp:69:23:69:43 | XercesDOMParser output argument | tests.cpp:74:2:74:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:69:23:69:43 | XercesDOMParser output argument | XML parser |
|
| tests3.cpp:63:2:63:2 | p | tests3.cpp:60:21:60:53 | call to createXMLReader | tests3.cpp:63:2:63:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests3.cpp:60:21:60:53 | call to createXMLReader | XML parser |
|
||||||
| tests.cpp:78:2:78:2 | p | tests.cpp:69:23:69:43 | XercesDOMParser output argument | tests.cpp:78:2:78:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:69:23:69:43 | XercesDOMParser output argument | XML parser |
|
| tests3.cpp:70:2:70:2 | p | tests3.cpp:67:21:67:53 | call to createXMLReader | tests3.cpp:70:2:70:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests3.cpp:67:21:67:53 | call to createXMLReader | XML parser |
|
||||||
| tests.cpp:87:2:87:2 | p | tests.cpp:84:23:84:43 | XercesDOMParser output argument | tests.cpp:87:2:87:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:84:23:84:43 | XercesDOMParser output argument | XML parser |
|
| tests4.cpp:26:34:26:48 | (int)... | tests4.cpp:26:34:26:48 | (int)... | tests4.cpp:26:34:26:48 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:26:34:26:48 | (int)... | XML parser |
|
||||||
| tests.cpp:98:2:98:2 | p | tests.cpp:91:23:91:43 | XercesDOMParser output argument | tests.cpp:98:2:98:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:91:23:91:43 | XercesDOMParser output argument | XML parser |
|
| tests4.cpp:36:34:36:50 | (int)... | tests4.cpp:36:34:36:50 | (int)... | tests4.cpp:36:34:36:50 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:36:34:36:50 | (int)... | XML parser |
|
||||||
| tests.cpp:106:3:106:3 | q | tests.cpp:103:24:103:44 | XercesDOMParser output argument | tests.cpp:106:3:106:3 | q | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:103:24:103:44 | XercesDOMParser output argument | XML parser |
|
| tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:46:34:46:68 | ... \| ... | XML parser |
|
||||||
| tests.cpp:122:3:122:3 | q | tests.cpp:118:24:118:44 | XercesDOMParser output argument | tests.cpp:122:3:122:3 | q | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:118:24:118:44 | XercesDOMParser output argument | XML parser |
|
| tests4.cpp:77:34:77:38 | flags | tests4.cpp:77:34:77:38 | flags | tests4.cpp:77:34:77:38 | flags | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:77:34:77:38 | flags | XML parser |
|
||||||
| tests.cpp:131:2:131:2 | p | tests.cpp:140:23:140:43 | XercesDOMParser output argument | tests.cpp:131:2:131:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:140:23:140:43 | XercesDOMParser output argument | XML parser |
|
| tests4.cpp:130:39:130:55 | (int)... | tests4.cpp:130:39:130:55 | (int)... | tests4.cpp:130:39:130:55 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:130:39:130:55 | (int)... | XML parser |
|
||||||
| tests.cpp:135:2:135:2 | p | tests.cpp:140:23:140:43 | XercesDOMParser output argument | tests.cpp:135:2:135:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:140:23:140:43 | XercesDOMParser output argument | XML parser |
|
| tests.cpp:17:2:17:2 | p | tests.cpp:15:23:15:43 | XercesDOMParser output argument | tests.cpp:17:2:17:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:15:23:15:43 | XercesDOMParser output argument | XML parser |
|
||||||
| tests.cpp:152:2:152:2 | p | tests.cpp:150:19:150:32 | call to createLSParser | tests.cpp:152:2:152:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:150:19:150:32 | call to createLSParser | XML parser |
|
| tests.cpp:31:2:31:2 | p | tests.cpp:28:23:28:43 | XercesDOMParser output argument | tests.cpp:31:2:31:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:28:23:28:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:39:2:39:2 | p | tests.cpp:35:23:35:43 | XercesDOMParser output argument | tests.cpp:39:2:39:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:35:23:35:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:56:2:56:2 | p | tests.cpp:51:23:51:43 | XercesDOMParser output argument | tests.cpp:56:2:56:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:51:23:51:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:60:2:60:2 | p | tests.cpp:51:23:51:43 | XercesDOMParser output argument | tests.cpp:60:2:60:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:51:23:51:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:69:2:69:2 | p | tests.cpp:66:23:66:43 | XercesDOMParser output argument | tests.cpp:69:2:69:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:66:23:66:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:80:2:80:2 | p | tests.cpp:73:23:73:43 | XercesDOMParser output argument | tests.cpp:80:2:80:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:73:23:73:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:88:3:88:3 | q | tests.cpp:85:24:85:44 | XercesDOMParser output argument | tests.cpp:88:3:88:3 | q | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:85:24:85:44 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:104:3:104:3 | q | tests.cpp:100:24:100:44 | XercesDOMParser output argument | tests.cpp:104:3:104:3 | q | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:100:24:100:44 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:113:2:113:2 | p | tests.cpp:122:23:122:43 | XercesDOMParser output argument | tests.cpp:113:2:113:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:122:23:122:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
| tests.cpp:117:2:117:2 | p | tests.cpp:122:23:122:43 | XercesDOMParser output argument | tests.cpp:117:2:117:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:122:23:122:43 | XercesDOMParser output argument | XML parser |
|
||||||
|
|||||||
@@ -1,32 +1,14 @@
|
|||||||
// test cases for rule CWE-611
|
// test cases for rule CWE-611 (XercesDOMParser)
|
||||||
|
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
class SecurityManager;
|
|
||||||
class InputSource;
|
|
||||||
|
|
||||||
class AbstractDOMParser {
|
|
||||||
public:
|
|
||||||
AbstractDOMParser();
|
|
||||||
|
|
||||||
void setDisableDefaultEntityResolution(bool); // default is false
|
|
||||||
void setCreateEntityReferenceNodes(bool); // default is true
|
|
||||||
void setSecurityManager(SecurityManager *const manager);
|
|
||||||
void parse(const InputSource &data);
|
|
||||||
};
|
|
||||||
|
|
||||||
class XercesDOMParser: public AbstractDOMParser {
|
class XercesDOMParser: public AbstractDOMParser {
|
||||||
public:
|
public:
|
||||||
XercesDOMParser();
|
XercesDOMParser();
|
||||||
};
|
};
|
||||||
|
|
||||||
class DOMLSParser : public AbstractDOMParser {
|
|
||||||
};
|
|
||||||
|
|
||||||
DOMLSParser *createLSParser();
|
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
void test1(InputSource &data) {
|
void test1(InputSource &data) {
|
||||||
@@ -145,26 +127,3 @@ void test10(InputSource &data) {
|
|||||||
test10_doParseC(p, data);
|
test10_doParseC(p, data);
|
||||||
test10_doParseC(q, data);
|
test10_doParseC(q, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test11(InputSource &data) {
|
|
||||||
DOMLSParser *p = createLSParser();
|
|
||||||
|
|
||||||
p->parse(data); // BAD (parser not correctly configured)
|
|
||||||
}
|
|
||||||
|
|
||||||
void test12(InputSource &data) {
|
|
||||||
DOMLSParser *p = createLSParser();
|
|
||||||
|
|
||||||
p->setDisableDefaultEntityResolution(true);
|
|
||||||
p->parse(data); // GOOD
|
|
||||||
}
|
|
||||||
|
|
||||||
DOMLSParser *g_p1 = createLSParser();
|
|
||||||
DOMLSParser *g_p2 = createLSParser();
|
|
||||||
InputSource *g_data;
|
|
||||||
|
|
||||||
void test13() {
|
|
||||||
g_p1->setDisableDefaultEntityResolution(true);
|
|
||||||
g_p1->parse(*g_data); // GOOD
|
|
||||||
g_p2->parse(*g_data); // BAD (parser not correctly configured) [NOT DETECTED]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,2 +1,26 @@
|
|||||||
// library functions for rule CWE-611
|
// library/common functions for rule CWE-611
|
||||||
|
|
||||||
|
#define NULL (0)
|
||||||
|
|
||||||
|
class SecurityManager;
|
||||||
|
class InputSource;
|
||||||
|
|
||||||
|
class AbstractDOMParser {
|
||||||
|
public:
|
||||||
|
AbstractDOMParser();
|
||||||
|
|
||||||
|
void setDisableDefaultEntityResolution(bool); // default is false
|
||||||
|
void setCreateEntityReferenceNodes(bool); // default is true
|
||||||
|
void setSecurityManager(SecurityManager *const manager);
|
||||||
|
void parse(const InputSource &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef unsigned int XMLCh;
|
||||||
|
|
||||||
|
class XMLUni
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const XMLCh fgXercesDisableDefaultEntityResolution[];
|
||||||
|
static const XMLCh fgXercesHarmlessOption[];
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
46
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests2.cpp
Normal file
46
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests2.cpp
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// test cases for rule CWE-611 (SAXParser)
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
class SAXParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SAXParser();
|
||||||
|
|
||||||
|
void setDisableDefaultEntityResolution(bool); // default is false
|
||||||
|
void setSecurityManager(SecurityManager *const manager);
|
||||||
|
void parse(const InputSource &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
void test2_1(InputSource &data) {
|
||||||
|
SAXParser *p = new SAXParser();
|
||||||
|
|
||||||
|
p->parse(data); // BAD (parser not correctly configured)
|
||||||
|
}
|
||||||
|
|
||||||
|
void test2_2(InputSource &data) {
|
||||||
|
SAXParser *p = new SAXParser();
|
||||||
|
|
||||||
|
p->setDisableDefaultEntityResolution(true);
|
||||||
|
p->parse(data); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test2_3(InputSource &data) {
|
||||||
|
SAXParser *p = new SAXParser();
|
||||||
|
bool v = false;
|
||||||
|
|
||||||
|
p->setDisableDefaultEntityResolution(v);
|
||||||
|
p->parse(data); // BAD (parser not correctly configured)
|
||||||
|
}
|
||||||
|
|
||||||
|
void test2_4(InputSource &data) {
|
||||||
|
SAXParser *p = new SAXParser();
|
||||||
|
bool v = true;
|
||||||
|
|
||||||
|
p->setDisableDefaultEntityResolution(v);
|
||||||
|
p->parse(data); // GOOD
|
||||||
|
}
|
||||||
82
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp
Normal file
82
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests3.cpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// test cases for rule CWE-611 (SAX2XMLReader)
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
class SAX2XMLReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setFeature(const XMLCh *feature, bool value);
|
||||||
|
void parse(const InputSource &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class XMLReaderFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static SAX2XMLReader *createXMLReader();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
void test3_1(InputSource &data) {
|
||||||
|
SAX2XMLReader *p = XMLReaderFactory::createXMLReader();
|
||||||
|
|
||||||
|
p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test3_2(InputSource &data) {
|
||||||
|
SAX2XMLReader *p = XMLReaderFactory::createXMLReader();
|
||||||
|
|
||||||
|
p->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);
|
||||||
|
p->parse(data); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
SAX2XMLReader *p_3_3 = XMLReaderFactory::createXMLReader();
|
||||||
|
|
||||||
|
void test3_3(InputSource &data) {
|
||||||
|
p_3_3->parse(data); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
SAX2XMLReader *p_3_4 = XMLReaderFactory::createXMLReader();
|
||||||
|
|
||||||
|
void test3_4(InputSource &data) {
|
||||||
|
p_3_4->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);
|
||||||
|
p_3_4->parse(data); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
SAX2XMLReader *p_3_5 = XMLReaderFactory::createXMLReader();
|
||||||
|
|
||||||
|
void test3_5_init() {
|
||||||
|
p_3_5->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test3_5(InputSource &data) {
|
||||||
|
test3_5_init();
|
||||||
|
p_3_5->parse(data); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test3_6(InputSource &data) {
|
||||||
|
SAX2XMLReader *p = XMLReaderFactory::createXMLReader();
|
||||||
|
|
||||||
|
p->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, false);
|
||||||
|
p->parse(data); // BAD (parser not correctly configured)
|
||||||
|
}
|
||||||
|
|
||||||
|
void test3_7(InputSource &data) {
|
||||||
|
SAX2XMLReader *p = XMLReaderFactory::createXMLReader();
|
||||||
|
|
||||||
|
p->setFeature(XMLUni::fgXercesHarmlessOption, true);
|
||||||
|
p->parse(data); // BAD (parser not correctly configured)
|
||||||
|
}
|
||||||
|
|
||||||
|
void test3_8(InputSource &data) {
|
||||||
|
SAX2XMLReader *p = XMLReaderFactory::createXMLReader();
|
||||||
|
const XMLCh *feature = XMLUni::fgXercesDisableDefaultEntityResolution;
|
||||||
|
|
||||||
|
p->setFeature(feature, true);
|
||||||
|
p->parse(data); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
135
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests4.cpp
Normal file
135
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests4.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// test cases for rule CWE-611 (libxml2)
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
enum xmlParserOption
|
||||||
|
{
|
||||||
|
XML_PARSE_NOENT = 2,
|
||||||
|
XML_PARSE_DTDLOAD = 4,
|
||||||
|
XML_PARSE_OPTION_HARMLESS = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
class xmlDoc;
|
||||||
|
|
||||||
|
xmlDoc *xmlReadFile(const char *fileName, const char *encoding, int flags);
|
||||||
|
xmlDoc *xmlReadMemory(const char *ptr, int sz, const char *url, const char *encoding, int flags);
|
||||||
|
|
||||||
|
void xmlFreeDoc(xmlDoc *ptr);
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
void test4_1(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, XML_PARSE_NOENT); // BAD (parser not correctly configured)
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_2(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, XML_PARSE_DTDLOAD); // BAD (parser not correctly configured)
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_3(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, XML_PARSE_NOENT | XML_PARSE_DTDLOAD); // BAD (parser not correctly configured)
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_4(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, 0); // GOOD
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_5(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, XML_PARSE_OPTION_HARMLESS); // GOOD
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_6(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
int flags = XML_PARSE_NOENT;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, flags); // BAD (parser not correctly configured)
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_7(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, flags); // GOOD
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_8(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
int flags = XML_PARSE_OPTION_HARMLESS;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, flags | XML_PARSE_NOENT); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_9(const char *fileName) {
|
||||||
|
xmlDoc *p;
|
||||||
|
int flags = XML_PARSE_NOENT;
|
||||||
|
|
||||||
|
p = xmlReadFile(fileName, NULL, flags | XML_PARSE_OPTION_HARMLESS); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_10(const char *ptr, int sz) {
|
||||||
|
xmlDoc *p;
|
||||||
|
|
||||||
|
p = xmlReadMemory(ptr, sz, "", NULL, 0); // GOOD
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test4_11(const char *ptr, int sz) {
|
||||||
|
xmlDoc *p;
|
||||||
|
|
||||||
|
p = xmlReadMemory(ptr, sz, "", NULL, XML_PARSE_DTDLOAD); // BAD (parser not correctly configured)
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
78
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests5.cpp
Normal file
78
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests5.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// test cases for rule CWE-611 (createLSParser)
|
||||||
|
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
class DOMConfiguration {
|
||||||
|
public:
|
||||||
|
void setParameter(const XMLCh *parameter, bool value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DOMLSParser {
|
||||||
|
public:
|
||||||
|
DOMConfiguration *getDomConfig();
|
||||||
|
|
||||||
|
void parse(const InputSource &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DOMImplementationLS {
|
||||||
|
public:
|
||||||
|
DOMLSParser *createLSParser();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
void test5_1(DOMImplementationLS *impl, InputSource &data) {
|
||||||
|
DOMLSParser *p = impl->createLSParser();
|
||||||
|
|
||||||
|
p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test5_2(DOMImplementationLS *impl, InputSource &data) {
|
||||||
|
DOMLSParser *p = impl->createLSParser();
|
||||||
|
|
||||||
|
p->getDomConfig()->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, true);
|
||||||
|
p->parse(data); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test5_3(DOMImplementationLS *impl, InputSource &data) {
|
||||||
|
DOMLSParser *p = impl->createLSParser();
|
||||||
|
|
||||||
|
p->getDomConfig()->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, false);
|
||||||
|
p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void test5_4(DOMImplementationLS *impl, InputSource &data) {
|
||||||
|
DOMLSParser *p = impl->createLSParser();
|
||||||
|
DOMConfiguration *cfg = p->getDomConfig();
|
||||||
|
|
||||||
|
cfg->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, true);
|
||||||
|
p->parse(data); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
void test5_5(DOMImplementationLS *impl, InputSource &data) {
|
||||||
|
DOMLSParser *p = impl->createLSParser();
|
||||||
|
DOMConfiguration *cfg = p->getDomConfig();
|
||||||
|
|
||||||
|
cfg->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, false);
|
||||||
|
p->parse(data); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMImplementationLS *g_impl;
|
||||||
|
DOMLSParser *g_p1, *g_p2;
|
||||||
|
InputSource *g_data;
|
||||||
|
|
||||||
|
void test5_6_init() {
|
||||||
|
g_p1 = g_impl->createLSParser();
|
||||||
|
g_p1->getDomConfig()->setParameter(XMLUni::fgXercesDisableDefaultEntityResolution, true);
|
||||||
|
|
||||||
|
g_p2 = g_impl->createLSParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test5_6() {
|
||||||
|
test5_6_init();
|
||||||
|
|
||||||
|
g_p1->parse(*g_data); // GOOD
|
||||||
|
g_p2->parse(*g_data); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
## 1.1.1
|
||||||
|
|
||||||
## 1.1.0
|
## 1.1.0
|
||||||
|
|
||||||
## 1.0.7
|
## 1.0.7
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
## 1.1.1
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 1.1.0
|
lastReleaseVersion: 1.1.1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-all
|
name: codeql/csharp-solorigate-all
|
||||||
version: 1.1.1-dev
|
version: 1.1.2-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
## 1.1.1
|
||||||
|
|
||||||
## 1.1.0
|
## 1.1.0
|
||||||
|
|
||||||
## 1.0.7
|
## 1.0.7
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
## 1.1.1
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 1.1.0
|
lastReleaseVersion: 1.1.1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-queries
|
name: codeql/csharp-solorigate-queries
|
||||||
version: 1.1.1-dev
|
version: 1.1.2-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* 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.1.0
|
## 0.1.0
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
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)`.
|
|
||||||
5
csharp/ql/lib/change-notes/released/0.2.0.md
Normal file
5
csharp/ql/lib/change-notes/released/0.2.0.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* 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)`.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.1.0
|
lastReleaseVersion: 0.2.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-all
|
name: codeql/csharp-all
|
||||||
version: 0.1.1-dev
|
version: 0.2.1-dev
|
||||||
groups: csharp
|
groups: csharp
|
||||||
dbscheme: semmlecode.csharp.dbscheme
|
dbscheme: semmlecode.csharp.dbscheme
|
||||||
extractor: csharp
|
extractor: csharp
|
||||||
|
|||||||
@@ -167,9 +167,16 @@ class AccessPathToken extends string {
|
|||||||
/** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
|
/** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
|
||||||
string getArgument(int n) { result = this.getArgumentList().splitAt(",", n).trim() }
|
string getArgument(int n) { result = this.getArgumentList().splitAt(",", n).trim() }
|
||||||
|
|
||||||
|
/** Gets the `n`th argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
|
||||||
|
pragma[nomagic]
|
||||||
|
string getArgument(string name, int n) { name = this.getName() and result = this.getArgument(n) }
|
||||||
|
|
||||||
/** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
|
/** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
|
||||||
string getAnArgument() { result = this.getArgument(_) }
|
string getAnArgument() { result = this.getArgument(_) }
|
||||||
|
|
||||||
|
/** Gets an argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
|
||||||
|
string getAnArgument(string name) { result = this.getArgument(name, _) }
|
||||||
|
|
||||||
/** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
|
/** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
|
||||||
int getNumArgument() { result = count(int n | exists(this.getArgument(n))) }
|
int getNumArgument() { result = count(int n | exists(this.getArgument(n))) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -498,23 +498,35 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
readSet(node1, cs, node2, config) and
|
readSet(node1, cs, node2, config) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline to reduce fan-out via `getAReadContent`
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
pragma[inline]
|
bindingset[c]
|
||||||
private predicate clearsContentEx(NodeEx n, Content c) {
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
exists(ContentSet cs |
|
exists(ContentSet cs |
|
||||||
clearsContentCached(n.asNode(), cs) and
|
clearsContentCached(n.asNode(), cs) and
|
||||||
c = cs.getAReadContent()
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
bindingset[c]
|
||||||
|
private predicate expectsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
expectsContentCached(n.asNode(), cs) and
|
||||||
|
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
@@ -793,7 +805,7 @@ private module Stage1 {
|
|||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
}
|
}
|
||||||
@@ -891,7 +903,7 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
@@ -1181,11 +1193,26 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
ap = true and
|
||||||
|
expectsContentCand(node, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -1646,10 +1673,24 @@ private module Stage2 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -1740,7 +1781,8 @@ private module LocalFlowBigStep {
|
|||||||
private class FlowCheckNode extends NodeEx {
|
private class FlowCheckNode extends NodeEx {
|
||||||
FlowCheckNode() {
|
FlowCheckNode() {
|
||||||
castNode(this.asNode()) or
|
castNode(this.asNode()) or
|
||||||
clearsContentCached(this.asNode(), _)
|
clearsContentCached(this.asNode(), _) or
|
||||||
|
expectsContentCached(this.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1979,6 +2021,16 @@ private module Stage3 {
|
|||||||
clearContent(node, ap.getHead().getContent(), config)
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
@@ -1987,7 +2039,12 @@ private module Stage3 {
|
|||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap, config) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
@@ -2452,10 +2509,24 @@ private module Stage3 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3279,10 +3350,24 @@ private module Stage4 {
|
|||||||
storeStepFwd(_, ap, tc, _, _, config)
|
storeStepFwd(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
private predicate revConsCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
storeStepCand(_, ap, tc, _, _, config)
|
storeStepCand(_, ap, tc, _, _, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate validAp(Ap ap, Configuration config) {
|
||||||
|
revFlow(_, _, _, _, ap, config) and ap instanceof ApNil
|
||||||
|
or
|
||||||
|
exists(TypedContent head, Ap tail |
|
||||||
|
consCand(head, tail, config) and
|
||||||
|
ap = apCons(head, tail)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||||
|
revConsCand(tc, ap, config) and
|
||||||
|
validAp(ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate parameterFlow(
|
private predicate parameterFlow(
|
||||||
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
ParamNodeEx p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||||
@@ -3351,17 +3436,28 @@ private Configuration unbindConf(Configuration conf) {
|
|||||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate nodeMayUseSummary(
|
pragma[nomagic]
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
private predicate nodeMayUseSummary0(
|
||||||
|
NodeEx n, DataFlowCallable c, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
Stage4::parameterMayFlowThrough(_, c, _, _) and
|
||||||
Stage4::revFlow(n, state, true, _, apa0, config) and
|
Stage4::revFlow(n, state, true, _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||||
n.getEnclosingCallable() = c
|
n.getEnclosingCallable() = c
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate nodeMayUseSummary(
|
||||||
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c |
|
||||||
|
Stage4::parameterMayFlowThrough(_, c, apa, config) and
|
||||||
|
nodeMayUseSummary0(n, c, state, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TSummaryCtx =
|
private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
@@ -4257,6 +4353,12 @@ private module Subpaths {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
|
||||||
|
succ = pred.getASuccessor() and
|
||||||
|
succNode = succ.getNodeEx()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||||
@@ -4264,15 +4366,13 @@ private module Subpaths {
|
|||||||
*/
|
*/
|
||||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
|
||||||
pragma[only_bind_into](arg).getASuccessor() = out0 and
|
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||||
subpaths03(arg, p, localStepToHidden*(ret), o, sout, apout) and
|
hasSuccessor(pragma[only_bind_into](arg), par, p) and
|
||||||
not ret.isHidden() and
|
not ret.isHidden() and
|
||||||
par.getNodeEx() = p and
|
pathNode(out0, o, sout, _, _, apout, _, _)
|
||||||
out0.getNodeEx() = o and
|
|
|
||||||
out0.getState() = sout and
|
out = out0 or out = out0.projectToSink()
|
||||||
out0.getAp() = apout and
|
|
||||||
(out = out0 or out = out0.projectToSink())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4609,6 +4709,10 @@ private module FlowExploration {
|
|||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentEx(node, ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead())
|
||||||
|
) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4625,6 +4729,10 @@ private module FlowExploration {
|
|||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentEx(node, ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node) or
|
||||||
|
expectsContentEx(node, ap.getHead().getContent())
|
||||||
|
) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
|
|||||||
@@ -328,6 +328,9 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||||
|
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
|||||||
or
|
or
|
||||||
exists(Ssa::Definition def |
|
exists(Ssa::Definition def |
|
||||||
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
|
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
|
||||||
not FlowSummaryImpl::Private::Steps::summaryClearsContentArg(nodeFrom, _) and
|
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom) and
|
||||||
not LocalFlow::usesInstanceField(def)
|
not LocalFlow::usesInstanceField(def)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -1714,6 +1714,14 @@ predicate clearsContent(Node n, Content c) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||||
|
* at node `n`.
|
||||||
|
*/
|
||||||
|
predicate expectsContent(Node n, ContentSet c) {
|
||||||
|
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n, c)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ module Public {
|
|||||||
string toString() {
|
string toString() {
|
||||||
exists(ContentSet c | this = TContentSummaryComponent(c) and result = c.toString())
|
exists(ContentSet c | this = TContentSummaryComponent(c) and result = c.toString())
|
||||||
or
|
or
|
||||||
|
exists(ContentSet c | this = TWithoutContentSummaryComponent(c) and result = "without " + c)
|
||||||
|
or
|
||||||
|
exists(ContentSet c | this = TWithContentSummaryComponent(c) and result = "with " + c)
|
||||||
|
or
|
||||||
exists(ArgumentPosition pos |
|
exists(ArgumentPosition pos |
|
||||||
this = TParameterSummaryComponent(pos) and result = "parameter " + pos
|
this = TParameterSummaryComponent(pos) and result = "parameter " + pos
|
||||||
)
|
)
|
||||||
@@ -43,6 +47,12 @@ module Public {
|
|||||||
/** Gets a summary component for content `c`. */
|
/** Gets a summary component for content `c`. */
|
||||||
SummaryComponent content(ContentSet c) { result = TContentSummaryComponent(c) }
|
SummaryComponent content(ContentSet c) { result = TContentSummaryComponent(c) }
|
||||||
|
|
||||||
|
/** Gets a summary component where data is not allowed to be stored in `c`. */
|
||||||
|
SummaryComponent withoutContent(ContentSet c) { result = TWithoutContentSummaryComponent(c) }
|
||||||
|
|
||||||
|
/** Gets a summary component where data must be stored in `c`. */
|
||||||
|
SummaryComponent withContent(ContentSet c) { result = TWithContentSummaryComponent(c) }
|
||||||
|
|
||||||
/** Gets a summary component for a parameter at position `pos`. */
|
/** Gets a summary component for a parameter at position `pos`. */
|
||||||
SummaryComponent parameter(ArgumentPosition pos) { result = TParameterSummaryComponent(pos) }
|
SummaryComponent parameter(ArgumentPosition pos) { result = TParameterSummaryComponent(pos) }
|
||||||
|
|
||||||
@@ -216,9 +226,16 @@ module Public {
|
|||||||
/**
|
/**
|
||||||
* Holds if values stored inside `content` are cleared on objects passed as
|
* Holds if values stored inside `content` are cleared on objects passed as
|
||||||
* arguments at position `pos` to this callable.
|
* arguments at position `pos` to this callable.
|
||||||
|
*
|
||||||
|
* TODO: Remove once all languages support `WithoutContent` tokens.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate clearsContent(ParameterPosition pos, ContentSet content) { none() }
|
predicate clearsContent(ParameterPosition pos, ContentSet content) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the summary is auto generated.
|
||||||
|
*/
|
||||||
|
predicate isAutoGenerated() { none() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +251,9 @@ module Private {
|
|||||||
TContentSummaryComponent(ContentSet c) or
|
TContentSummaryComponent(ContentSet c) or
|
||||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||||
TReturnSummaryComponent(ReturnKind rk)
|
TReturnSummaryComponent(ReturnKind rk) or
|
||||||
|
TWithoutContentSummaryComponent(ContentSet c) or
|
||||||
|
TWithContentSummaryComponent(ContentSet c)
|
||||||
|
|
||||||
private TParameterSummaryComponent thisParam() {
|
private TParameterSummaryComponent thisParam() {
|
||||||
result = TParameterSummaryComponent(instanceParameterPosition())
|
result = TParameterSummaryComponent(instanceParameterPosition())
|
||||||
@@ -296,6 +315,23 @@ module Private {
|
|||||||
SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and
|
SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and
|
||||||
preservesValue = preservesValue1.booleanAnd(preservesValue2)
|
preservesValue = preservesValue1.booleanAnd(preservesValue2)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(ParameterPosition ppos, ContentSet cs |
|
||||||
|
c.clearsContent(ppos, cs) and
|
||||||
|
input = SummaryComponentStack::push(SummaryComponent::withoutContent(cs), output) and
|
||||||
|
output = SummaryComponentStack::argument(ppos) and
|
||||||
|
preservesValue = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MkClearStack extends RequiredSummaryComponentStack {
|
||||||
|
override predicate required(SummaryComponent head, SummaryComponentStack tail) {
|
||||||
|
exists(SummarizedCallable sc, ParameterPosition ppos, ContentSet cs |
|
||||||
|
sc.clearsContent(ppos, cs) and
|
||||||
|
head = SummaryComponent::withoutContent(cs) and
|
||||||
|
tail = SummaryComponentStack::argument(ppos)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -378,10 +414,7 @@ module Private {
|
|||||||
|
|
||||||
private newtype TSummaryNodeState =
|
private newtype TSummaryNodeState =
|
||||||
TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or
|
TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or
|
||||||
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } or
|
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) }
|
||||||
TSummaryNodeClearsContentState(ParameterPosition pos, boolean post) {
|
|
||||||
any(SummarizedCallable sc).clearsContent(pos, _) and post in [false, true]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A state used to break up (complex) flow summaries into atomic flow steps.
|
* A state used to break up (complex) flow summaries into atomic flow steps.
|
||||||
@@ -428,12 +461,6 @@ module Private {
|
|||||||
this = TSummaryNodeOutputState(s) and
|
this = TSummaryNodeOutputState(s) and
|
||||||
result = "to write: " + s
|
result = "to write: " + s
|
||||||
)
|
)
|
||||||
or
|
|
||||||
exists(ParameterPosition pos, boolean post, string postStr |
|
|
||||||
this = TSummaryNodeClearsContentState(pos, post) and
|
|
||||||
(if post = true then postStr = " (post)" else postStr = "") and
|
|
||||||
result = "clear: " + pos + postStr
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,11 +484,6 @@ module Private {
|
|||||||
not parameterReadState(c, state, _)
|
not parameterReadState(c, state, _)
|
||||||
or
|
or
|
||||||
state.isOutputState(c, _)
|
state.isOutputState(c, _)
|
||||||
or
|
|
||||||
exists(ParameterPosition pos |
|
|
||||||
c.clearsContent(pos, _) and
|
|
||||||
state = TSummaryNodeClearsContentState(pos, _)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
@@ -497,8 +519,6 @@ module Private {
|
|||||||
parameterReadState(c, _, pos)
|
parameterReadState(c, _, pos)
|
||||||
or
|
or
|
||||||
isParameterPostUpdate(_, c, pos)
|
isParameterPostUpdate(_, c, pos)
|
||||||
or
|
|
||||||
c.clearsContent(pos, _)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackOutput(
|
private predicate callbackOutput(
|
||||||
@@ -506,7 +526,7 @@ module Private {
|
|||||||
) {
|
) {
|
||||||
any(SummaryNodeState state).isInputState(c, s) and
|
any(SummaryNodeState state).isInputState(c, s) and
|
||||||
s.head() = TReturnSummaryComponent(rk) and
|
s.head() = TReturnSummaryComponent(rk) and
|
||||||
receiver = summaryNodeInputState(c, s.drop(1))
|
receiver = summaryNodeInputState(c, s.tail())
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackInput(
|
private predicate callbackInput(
|
||||||
@@ -514,7 +534,7 @@ module Private {
|
|||||||
) {
|
) {
|
||||||
any(SummaryNodeState state).isOutputState(c, s) and
|
any(SummaryNodeState state).isOutputState(c, s) and
|
||||||
s.head() = TParameterSummaryComponent(pos) and
|
s.head() = TParameterSummaryComponent(pos) and
|
||||||
receiver = summaryNodeInputState(c, s.drop(1))
|
receiver = summaryNodeInputState(c, s.tail())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
|
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
|
||||||
@@ -540,15 +560,21 @@ module Private {
|
|||||||
exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() |
|
exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() |
|
||||||
n = summaryNodeInputState(c, s) and
|
n = summaryNodeInputState(c, s) and
|
||||||
(
|
(
|
||||||
|
exists(ContentSet cont | result = getContentType(cont) |
|
||||||
|
head = TContentSummaryComponent(cont) or
|
||||||
|
head = TWithContentSummaryComponent(cont)
|
||||||
|
)
|
||||||
|
or
|
||||||
exists(ContentSet cont |
|
exists(ContentSet cont |
|
||||||
head = TContentSummaryComponent(cont) and result = getContentType(cont)
|
head = TWithoutContentSummaryComponent(cont) and
|
||||||
|
result = getNodeType(summaryNodeInputState(c, s.tail()))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(ReturnKind rk |
|
exists(ReturnKind rk |
|
||||||
head = TReturnSummaryComponent(rk) and
|
head = TReturnSummaryComponent(rk) and
|
||||||
result =
|
result =
|
||||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.drop(1))), rk)
|
s.tail())), rk)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -567,16 +593,10 @@ module Private {
|
|||||||
exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) |
|
exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) |
|
||||||
result =
|
result =
|
||||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||||
s.drop(1))), pos)
|
s.tail())), pos)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
|
||||||
exists(SummarizedCallable c, ParameterPosition pos, ParamNode p |
|
|
||||||
n = summaryNode(c, TSummaryNodeClearsContentState(pos, false)) and
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
result = getNodeType(p)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if summary node `out` contains output of kind `rk` from call `c`. */
|
/** Holds if summary node `out` contains output of kind `rk` from call `c`. */
|
||||||
@@ -602,9 +622,6 @@ module Private {
|
|||||||
exists(SummarizedCallable c, ParameterPosition pos |
|
exists(SummarizedCallable c, ParameterPosition pos |
|
||||||
isParameterPostUpdate(post, c, pos) and
|
isParameterPostUpdate(post, c, pos) and
|
||||||
pre.(ParamNode).isParameterOf(c, pos)
|
pre.(ParamNode).isParameterOf(c, pos)
|
||||||
or
|
|
||||||
pre = summaryNode(c, TSummaryNodeClearsContentState(pos, false)) and
|
|
||||||
post = summaryNode(c, TSummaryNodeClearsContentState(pos, true))
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(SummarizedCallable callable, SummaryComponentStack s |
|
exists(SummarizedCallable callable, SummaryComponentStack s |
|
||||||
@@ -628,8 +645,6 @@ module Private {
|
|||||||
*/
|
*/
|
||||||
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
|
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
|
||||||
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(c, ppos) |
|
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(c, ppos) |
|
||||||
c.clearsContent(ppos, _)
|
|
||||||
or
|
|
||||||
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
|
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
|
||||||
summary(c, inputContents, outputContents, _) and
|
summary(c, inputContents, outputContents, _) and
|
||||||
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
|
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
|
||||||
@@ -658,9 +673,10 @@ module Private {
|
|||||||
preservesValue = false and not summary(c, inputContents, outputContents, true)
|
preservesValue = false and not summary(c, inputContents, outputContents, true)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(SummarizedCallable c, ParameterPosition pos |
|
exists(SummarizedCallable c, SummaryComponentStack s |
|
||||||
pred.(ParamNode).isParameterOf(c, pos) and
|
pred = summaryNodeInputState(c, s.tail()) and
|
||||||
succ = summaryNode(c, TSummaryNodeClearsContentState(pos, _)) and
|
succ = summaryNodeInputState(c, s) and
|
||||||
|
s.head() = [SummaryComponent::withContent(_), SummaryComponent::withoutContent(_)] and
|
||||||
preservesValue = true
|
preservesValue = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -671,7 +687,7 @@ module Private {
|
|||||||
*/
|
*/
|
||||||
predicate summaryReadStep(Node pred, ContentSet c, Node succ) {
|
predicate summaryReadStep(Node pred, ContentSet c, Node succ) {
|
||||||
exists(SummarizedCallable sc, SummaryComponentStack s |
|
exists(SummarizedCallable sc, SummaryComponentStack s |
|
||||||
pred = summaryNodeInputState(sc, s.drop(1)) and
|
pred = summaryNodeInputState(sc, s.tail()) and
|
||||||
succ = summaryNodeInputState(sc, s) and
|
succ = summaryNodeInputState(sc, s) and
|
||||||
SummaryComponent::content(c) = s.head()
|
SummaryComponent::content(c) = s.head()
|
||||||
)
|
)
|
||||||
@@ -684,7 +700,7 @@ module Private {
|
|||||||
predicate summaryStoreStep(Node pred, ContentSet c, Node succ) {
|
predicate summaryStoreStep(Node pred, ContentSet c, Node succ) {
|
||||||
exists(SummarizedCallable sc, SummaryComponentStack s |
|
exists(SummarizedCallable sc, SummaryComponentStack s |
|
||||||
pred = summaryNodeOutputState(sc, s) and
|
pred = summaryNodeOutputState(sc, s) and
|
||||||
succ = summaryNodeOutputState(sc, s.drop(1)) and
|
succ = summaryNodeOutputState(sc, s.tail()) and
|
||||||
SummaryComponent::content(c) = s.head()
|
SummaryComponent::content(c) = s.head()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -709,9 +725,22 @@ module Private {
|
|||||||
* node where field `b` is cleared).
|
* node where field `b` is cleared).
|
||||||
*/
|
*/
|
||||||
predicate summaryClearsContent(Node n, ContentSet c) {
|
predicate summaryClearsContent(Node n, ContentSet c) {
|
||||||
exists(SummarizedCallable sc, ParameterPosition pos |
|
exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack |
|
||||||
n = summaryNode(sc, TSummaryNodeClearsContentState(pos, true)) and
|
n = summaryNode(sc, state) and
|
||||||
sc.clearsContent(pos, c)
|
state.isInputState(sc, stack) and
|
||||||
|
stack.head() = SummaryComponent::withoutContent(c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the value that is being tracked is expected to be stored inside
|
||||||
|
* content `c` at `n`.
|
||||||
|
*/
|
||||||
|
predicate summaryExpectsContent(Node n, ContentSet c) {
|
||||||
|
exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack |
|
||||||
|
n = summaryNode(sc, state) and
|
||||||
|
state.isInputState(sc, stack) and
|
||||||
|
stack.head() = SummaryComponent::withContent(c)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,22 +752,6 @@ module Private {
|
|||||||
sc = viableCallable(call)
|
sc = viableCallable(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if values stored inside content `c` are cleared inside a
|
|
||||||
* callable to which `arg` is an argument.
|
|
||||||
*
|
|
||||||
* In such cases, it is important to prevent use-use flow out of
|
|
||||||
* `arg` (see comment for `summaryClearsContent`).
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
predicate summaryClearsContentArg(ArgNode arg, ContentSet c) {
|
|
||||||
exists(DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos |
|
|
||||||
argumentPositionMatch(call, arg, ppos) and
|
|
||||||
viableParam(call, sc, ppos, _) and
|
|
||||||
sc.clearsContent(ppos, c)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg) {
|
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg) {
|
||||||
exists(ParameterPosition ppos, SummarizedCallable sc |
|
exists(ParameterPosition ppos, SummarizedCallable sc |
|
||||||
@@ -747,6 +760,27 @@ module Private {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if use-use flow starting from `arg` should be prohibited.
|
||||||
|
*
|
||||||
|
* This is the case when `arg` is the argument of a call that targets a
|
||||||
|
* flow summary where the corresponding parameter either clears contents
|
||||||
|
* or expects contents.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate prohibitsUseUseFlow(ArgNode arg) {
|
||||||
|
exists(ParamNode p, Node mid, ParameterPosition ppos, Node ret |
|
||||||
|
p = summaryArgParam0(_, arg) and
|
||||||
|
p.isParameterOf(_, ppos) and
|
||||||
|
summaryLocalStep(p, mid, true) and
|
||||||
|
summaryLocalStep(mid, ret, true) and
|
||||||
|
isParameterPostUpdate(ret, _, ppos)
|
||||||
|
|
|
||||||
|
summaryClearsContent(mid, _) or
|
||||||
|
summaryExpectsContent(mid, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
|
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
|
||||||
exists(DataFlowCall call |
|
exists(DataFlowCall call |
|
||||||
@@ -898,6 +932,8 @@ module Private {
|
|||||||
kind = "taint" and preservesValue = false
|
kind = "taint" and preservesValue = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override predicate isAutoGenerated() { summaryElement(this, _, _, _, true) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if component `c` of specification `spec` cannot be parsed. */
|
/** Holds if component `c` of specification `spec` cannot be parsed. */
|
||||||
@@ -1052,9 +1088,13 @@ module Private {
|
|||||||
preservesValue = false and result = "taint"
|
preservesValue = false and result = "taint"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string renderGenerated(RelevantSummarizedCallable c) {
|
||||||
|
if c.isAutoGenerated() then result = "generated:" else result = ""
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
||||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind",
|
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;(generated:)?kind",
|
||||||
* ext is hardcoded to empty.
|
* ext is hardcoded to empty.
|
||||||
*/
|
*/
|
||||||
query predicate summary(string csv) {
|
query predicate summary(string csv) {
|
||||||
@@ -1065,7 +1105,7 @@ module Private {
|
|||||||
c.relevantSummary(input, output, preservesValue) and
|
c.relevantSummary(input, output, preservesValue) and
|
||||||
csv =
|
csv =
|
||||||
c.getCallableCsv() + getComponentStackCsv(input) + ";" + getComponentStackCsv(output) +
|
c.getCallableCsv() + getComponentStackCsv(input) + ";" + getComponentStackCsv(output) +
|
||||||
";" + renderKind(preservesValue)
|
";" + renderGenerated(c) + renderKind(preservesValue)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1141,6 +1181,10 @@ module Private {
|
|||||||
Private::Steps::summaryClearsContent(a.asNode(), c) and
|
Private::Steps::summaryClearsContent(a.asNode(), c) and
|
||||||
b = a and
|
b = a and
|
||||||
value = "clear (" + c + ")"
|
value = "clear (" + c + ")"
|
||||||
|
or
|
||||||
|
Private::Steps::summaryExpectsContent(a.asNode(), c) and
|
||||||
|
b = a and
|
||||||
|
value = "expect (" + c + ")"
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
summaryPostUpdateNode(b.asNode(), a.asNode()) and
|
summaryPostUpdateNode(b.asNode(), a.asNode()) and
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ private predicate unknownSign(Expr e) {
|
|||||||
or
|
or
|
||||||
exists(LongLiteral lit | lit = e and not exists(lit.getValue().toFloat()))
|
exists(LongLiteral lit | lit = e and not exists(lit.getValue().toFloat()))
|
||||||
or
|
or
|
||||||
exists(CastExpr cast, Type fromtyp |
|
exists(CastingExpr cast, Type fromtyp |
|
||||||
cast = e and
|
cast = e and
|
||||||
fromtyp = cast.getSourceType() and
|
fromtyp = cast.getSourceType() and
|
||||||
not fromtyp instanceof NumericOrCharType
|
not fromtyp instanceof NumericOrCharType
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ module Private {
|
|||||||
|
|
||||||
class CastExpr = RU::ExprNode::CastExpr;
|
class CastExpr = RU::ExprNode::CastExpr;
|
||||||
|
|
||||||
|
class CastingExpr = CastExpr;
|
||||||
|
|
||||||
class Type = CS::Type;
|
class Type = CS::Type;
|
||||||
|
|
||||||
class Expr = CS::ControlFlow::Nodes::ExprNode;
|
class Expr = CS::ControlFlow::Nodes::ExprNode;
|
||||||
|
|||||||
@@ -175,8 +175,8 @@ class Call extends DotNet::Call, Expr, @call {
|
|||||||
* - Line 10: The static target is `Type.InvokeMember()`, whereas the run-time targets
|
* - Line 10: The static target is `Type.InvokeMember()`, whereas the run-time targets
|
||||||
* are both `A.M()` and `B.M()`.
|
* are both `A.M()` and `B.M()`.
|
||||||
*
|
*
|
||||||
* - Line 16: There is no static target (delegate call) but the delegate `i => { }` (line
|
* - Line 16: There is no static target (delegate call) but the delegate `i => { }`
|
||||||
* 20) is a run-time target.
|
* (line 20) is a run-time target.
|
||||||
*/
|
*/
|
||||||
override Callable getARuntimeTarget() {
|
override Callable getARuntimeTarget() {
|
||||||
exists(DispatchCall dc | dc.getCall() = this | result = dc.getADynamicTarget())
|
exists(DispatchCall dc | dc.getCall() = this | result = dc.getADynamicTarget())
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ private class SystemCollectionsIEnumerableClearFlow extends SummarizedCallable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) {
|
override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) {
|
||||||
pos.isThisParameter() and
|
(if this.(Modifiable).isStatic() then pos.getPosition() = 0 else pos.isThisParameter()) and
|
||||||
content instanceof DataFlow::ElementContent
|
content instanceof DataFlow::ElementContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Potentially incorrect CompareTo(...) signature
|
* @name Potentially incorrect CompareTo(...) signature
|
||||||
* @description The declaring type of a method with signature 'CompareTo(T)' does not implement 'IComparable<T>'.
|
* @description The declaring type of a method with signature `CompareTo(T)` does not implement `IComparable<T>`.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
* @precision medium
|
* @precision medium
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
## 0.1.1
|
||||||
|
|
||||||
## 0.1.0
|
## 0.1.0
|
||||||
|
|
||||||
## 0.0.13
|
## 0.0.13
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Incorrect parameter name in documentation
|
* @name Incorrect parameter name in documentation
|
||||||
* @description The parameter name given in a '<param>' tag does not exist. Rename the parameter or
|
* @description The parameter name given in a `<param>` tag does not exist. Rename the parameter or
|
||||||
* change the name in the documentation to ensure that they are the same.
|
* change the name in the documentation to ensure that they are the same.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity recommendation
|
* @problem.severity recommendation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Incorrect type parameter name in documentation
|
* @name Incorrect type parameter name in documentation
|
||||||
* @description The type parameter name given in a '<typeparam>' tag does not exist. Rename the parameter or
|
* @description The type parameter name given in a `<typeparam>` tag does not exist. Rename the parameter or
|
||||||
* change the name in the documentation to ensure that they are the same.
|
* change the name in the documentation to ensure that they are the same.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity recommendation
|
* @problem.severity recommendation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Missing documentation for exception
|
* @name Missing documentation for exception
|
||||||
* @description Exceptions thrown by the method should be documented using '<exception cref="..."> </exception>' tags.
|
* @description Exceptions thrown by the method should be documented using `<exception cref="..."> </exception>` tags.
|
||||||
* Ensure that the correct type of the exception is given in the 'cref' attribute.
|
* Ensure that the correct type of the exception is given in the 'cref' attribute.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity recommendation
|
* @problem.severity recommendation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Missing documentation for parameter
|
* @name Missing documentation for parameter
|
||||||
* @description All parameters should be documented using '<param name="..."> </param>' tags.
|
* @description All parameters should be documented using `<param name="..."> </param>` tags.
|
||||||
* Ensure that the name attribute matches the name of the parameter.
|
* Ensure that the name attribute matches the name of the parameter.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity recommendation
|
* @problem.severity recommendation
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @name Missing documentation for return value
|
* @name Missing documentation for return value
|
||||||
* @description The method returns a value, but the return value is not documented using
|
* @description The method returns a value, but the return value is not documented using
|
||||||
* a '<returns>' tag.
|
* a `<returns>` tag.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity recommendation
|
* @problem.severity recommendation
|
||||||
* @precision low
|
* @precision low
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Missing a summary in documentation comment
|
* @name Missing a summary in documentation comment
|
||||||
* @description The documentation comment does not contain a '<summary>' tag.
|
* @description The documentation comment does not contain a `<summary>` tag.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity recommendation
|
* @problem.severity recommendation
|
||||||
* @precision high
|
* @precision high
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Missing documentation for type parameter
|
* @name Missing documentation for type parameter
|
||||||
* @description All type parameters should be documented using '<typeparam name="..."> </typeparam>' tags.
|
* @description All type parameters should be documented using `<typeparam name="..."> </typeparam>` tags.
|
||||||
* Ensure that the 'name' attribute matches the name of the type parameter.
|
* Ensure that the 'name' attribute matches the name of the type parameter.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity recommendation
|
* @problem.severity recommendation
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name XML injection
|
* @name XML injection
|
||||||
* @description Building an XML document from user-controlled sources is vulnerable to insertion of
|
* @description Building an XML document from user-controlled sources is vulnerable to insertion of
|
||||||
* malicious code by the user.
|
* malicious code by the user.
|
||||||
* @kind problem
|
* @kind path-problem
|
||||||
* @id cs/xml-injection
|
* @id cs/xml-injection
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @security-severity 8.8
|
* @security-severity 8.8
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
|
import DataFlow::PathGraph
|
||||||
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
import semmle.code.csharp.frameworks.system.Xml
|
import semmle.code.csharp.frameworks.system.Xml
|
||||||
|
|
||||||
@@ -45,6 +46,6 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from TaintTrackingConfiguration c, DataFlow::Node source, DataFlow::Node sink
|
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||||
where c.hasFlow(source, sink)
|
where c.hasFlowPath(source, sink)
|
||||||
select sink, "$@ flows to here and is inserted as XML.", source, "User-provided value"
|
select sink, source, sink, "$@ flows to here and is inserted as XML.", source, "User-provided value"
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ if (version != "latest"):
|
|||||||
cmd.append(version)
|
cmd.append(version)
|
||||||
run_cmd(cmd)
|
run_cmd(cmd)
|
||||||
|
|
||||||
sdk_version = '6.0.101'
|
sdk_version = '6.0.202'
|
||||||
print("\n* Creating new global.json file and setting SDK to " + sdk_version)
|
print("\n* Creating new global.json file and setting SDK to " + sdk_version)
|
||||||
run_cmd(['dotnet', 'new', 'globaljson', '--force', '--sdk-version', sdk_version, '--output', workDir])
|
run_cmd(['dotnet', 'new', 'globaljson', '--force', '--sdk-version', sdk_version, '--output', workDir])
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name External libraries
|
* @name External libraries
|
||||||
* @description A list of external libraries used in the code
|
* @description A list of external libraries used in the code
|
||||||
* @kind metric
|
* @kind metric
|
||||||
* @tags summary
|
* @tags summary telemetry
|
||||||
* @id csharp/telemetry/external-libs
|
* @id csharp/telemetry/external-libs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name Supported sinks in external libraries
|
* @name Supported sinks in external libraries
|
||||||
* @description A list of 3rd party APIs detected as sinks. Excludes APIs exposed by test libraries.
|
* @description A list of 3rd party APIs detected as sinks. Excludes APIs exposed by test libraries.
|
||||||
* @kind metric
|
* @kind metric
|
||||||
* @tags summary
|
* @tags summary telemetry
|
||||||
* @id csharp/telemetry/supported-external-api-sinks
|
* @id csharp/telemetry/supported-external-api-sinks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name Supported sources in external libraries
|
* @name Supported sources in external libraries
|
||||||
* @description A list of 3rd party APIs detected as sources. Excludes APIs exposed by test libraries.
|
* @description A list of 3rd party APIs detected as sources. Excludes APIs exposed by test libraries.
|
||||||
* @kind metric
|
* @kind metric
|
||||||
* @tags summary
|
* @tags summary telemetry
|
||||||
* @id csharp/telemetry/supported-external-api-sources
|
* @id csharp/telemetry/supported-external-api-sources
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name Supported flow steps in external libraries
|
* @name Supported flow steps in external libraries
|
||||||
* @description A list of 3rd party APIs detected as flow steps. Excludes APIs exposed by test libraries.
|
* @description A list of 3rd party APIs detected as flow steps. Excludes APIs exposed by test libraries.
|
||||||
* @kind metric
|
* @kind metric
|
||||||
* @tags summary
|
* @tags summary telemetry
|
||||||
* @id csharp/telemetry/supported-external-api-taint
|
* @id csharp/telemetry/supported-external-api-taint
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @name Usage of unsupported APIs coming from external libraries
|
* @name Usage of unsupported APIs coming from external libraries
|
||||||
* @description A list of 3rd party APIs used in the codebase. Excludes APIs exposed by test libraries.
|
* @description A list of 3rd party APIs used in the codebase. Excludes APIs exposed by test libraries.
|
||||||
* @kind metric
|
* @kind metric
|
||||||
* @tags summary
|
* @tags summary telemetry
|
||||||
* @id csharp/telemetry/unsupported-external-api
|
* @id csharp/telemetry/unsupported-external-api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
1
csharp/ql/src/change-notes/released/0.1.1.md
Normal file
1
csharp/ql/src/change-notes/released/0.1.1.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
## 0.1.1
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user